Example #1
0
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;

}
Example #2
0
void sendReplay(aeEventLoop *el, int fd, void *privdata, int mask)
{
    vuiClient *c = (vuiClient *)privdata;
    int len;
    int nw;
    char *pos;
    sdsclear(c->res.buf);
    LogInfo("sendReplay....");
    c->res.buf = sdscatprintf(c->res.buf, "%s %d %s\r\nlength: %zu\r\n\r\n%s",
            c->res.version, c->res.code, c->res.reason, 
            sdslen(c->res.body),
            c->res.body);
    len = sdslen(c->res.buf);
    pos = c->res.buf;
    while(len>0)
    {
        nw = write(fd, pos, len);
        pos +=  nw;
        len -= nw;
    }

    //reset
    if (c->res.code >= 200)
    {
        c->procing = PROC_END;
    }
    else{
        c->res.code = 200;
        c->res.reason = sdscpy(c->res.reason, "OK");
        c->procing = PROC_ING;
    }
    aeDeleteFileEvent(el,c->fd,AE_WRITABLE);
}
Example #3
0
static void
client_cb(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask) {
    struct node *client = (struct node *)clientData;

    /* read */
    char buffer[512];
    int len = read(fd, buffer, 512);
    if (len <= 0) {
        fprintf(stderr, "Client closed: %d.", fd);
        aeDeleteFileEvent(eventLoop, fd, mask);
        client_remove(client);
        return;
    }

    /* push to total and split */
    int count = 0;
    client->buffer = sdscatlen(client->buffer, buffer, len);
    sds *lines = sdssplitlen(client->buffer, sdslen(client->buffer), "\n", 1, &count);

    /* translate */
    int i;
    for (i = 0; i < count; i++) {
        translate(lines[i], client);
        sdsfree(lines[i]);
    }
    free(lines);

    sdsclear(client->buffer);
}
Example #4
0
/* Tokenize a given sds, setting a term to zero-length sds if it's
 * a stopword. A total number of tokens and total number of nonstopwords
 * will be returned */
static sds *sds_tokenize(sds s, int *len, int *nonstopwords) {
    int i, l, k;
    sds *terms;
    struct stemmer *stmer;

    *nonstopwords = 0;
    terms = sdssplitlen(s, sdslen(s), " ", 1, len);
    if (!terms) return NULL;
    stmer = create_stemmer();
    for (i = 0; i < *len; i++) {
        sds stemmed = NULL, term = terms[i];
        term = sdstrim(term, puncs);
        l = sdslen(term);
        sdstolower(term);
        if (l == 0 || rr_stopwords_check(term)) {
            sdsclear(term);
            continue;
        }
        *nonstopwords += 1;
        /* note that the third argument is a zero-based index */
        k = stem(stmer, term, l-1);
        if (k < l-1) {
            stemmed = sdsnewlen(term, k+1);
            sdsfree(term);
            terms[i] = stemmed;
        }
    }

    free_stemmer(stmer);
    return terms;
}
Example #5
0
void addReplay(vuiClient *c, const char *body)
{
    if (body) c->res.body = sdscpy(c->res.body, body);
    else
        sdsclear(c->res.body);
    c->procing = PROC_HALF;
    aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, sendReplay, c);
}
Example #6
0
int main(int argc, char **argv){
	if(argc!=3){
		printf("Wrong arguments\n");
	}
	char *addr=argv[1];
	int port=strtol(argv[2],NULL,10);
	redisContext *c=redisConnect(addr,port);
	if(c!=NULL && c->err){
		printf("Error: %s\n", c->errstr);
		return 1;
	}
	printf("RESP> ");
	sds buf=sdsempty();
	if(buf==NULL){
		printf("%s\n", "out of memory");
	}
	while(1){
		buf=getlinefromconsolo(buf);
		redisReply *reply= redisCommand(c, buf);
		sdsclear(buf);
		int type=reply->type;
		switch(type){
			case REDIS_REPLY_STRING:
			case REDIS_REPLY_ERROR:
			case REDIS_REPLY_INTEGER:
			case REDIS_REPLY_NIL:
			case REDIS_REPLY_STATUS:
				processLineReply(reply,&buf);
				break;
			case REDIS_REPLY_ARRAY:
				processMultiBulkReply(reply,&buf);
				break;
			default:
				printf("%s\n", "Unkown reply type");
		}
		printf("%s\n", buf);
		sdsclear(buf);
		printf("RESP> ");
	}
	return 0;
}
Example #7
0
void  processInputBuffer(vuiClient *c)
{
    int res;
    char *buf;
    int len;

    buf = c->querybuf;
    len = sdslen(c->querybuf);

    if (c->prot.waiting)
    {
        if (len >= c->prot.waiting)
        {
            c->querymsg = sdscatlen(c->querymsg, buf, c->prot.waiting);
            buf += c->prot.waiting;
            c->prot.waiting = 0;
            goto deal;
        }
        else
        {
            c->querymsg = sdscatlen(c->querymsg, buf, len);
            c->prot.waiting -= len;
            goto clear;
        }
    }

    while((buf = strstr(buf, REQUEST_POST " ")))//找报文头
    {
        res = resloveMessage(&buf, c);
        switch(res)
        {
            case -3:
                goto clear;
            case -2://contiune read
                if (buf != c->querybuf)
                {
                    sdsrange(c->querybuf, buf - c->querybuf, -1);
                }
                goto res;
            case 0:
deal:
                c->prot.body = c->querymsg + c->prot.hlenght;
                processRequest(c);
            case -1:
                break;
        }
    }
clear:
    sdsclear(c->querybuf);
res:
    return;
}
Example #8
0
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
    vuiClient *c = (vuiClient *) privdata;
    int nread, readlen;
    size_t qblen;

    /* If this is a multi bulk request, and we are processing a bulk reply
     * that is large enough, try to maximize the probability that the query
     * buffer contains exactly the SDS string representing the object, even
     * at the risk of requiring more read(2) calls. This way the function
     * processMultiBulkBuffer() can avoid copying buffers to create the
     * Redis Object representing the argument. */
    if (c->prot.waiting)
    {
        readlen = c->prot.waiting;
    }
    else
    {
        readlen = 1024 * 2;
    }

    qblen = sdslen(c->querybuf);
    c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);
    nread = read(fd, c->querybuf+qblen, readlen);

    if (nread == -1) {
        if (errno == EAGAIN) {
            nread = 0;
        } else {
            LogInfo("Reading from client: %s",strerror(errno));
            freeClient(c);
            return;
        }
    } else if (nread == 0) {
        LogInfo("Client closed connection");
        freeClient(c);
        return;
    }
    if (nread) {
        sdsIncrLen(c->querybuf,nread);
    } 
    //TODO
    if (sdslen(c->querybuf) > 1024 * 1024) {
        LogWarn("Closing client that reached max query buffer length");
        sdsclear(c->querybuf);
        freeClient(c);
        return;
    }
    processInputBuffer(c);
}
Example #9
0
/* Returns 1 or 0 for success/failure.
 * The function returns success as long as we are able to correctly write
 * to at least one file descriptor.
 *
 * When buf is NULL and len is 0, the function performs a flush operation
 * if there is some pending buffer, so this function is also used in order
 * to implement rioFdsetFlush(). */
static size_t rioFdsetWrite(rio *r, const void *buf, size_t len) {
    ssize_t retval;
    int j;
    unsigned char *p = (unsigned char*) buf;
    int doflush = (buf == NULL && len == 0);

    /* To start we always append to our buffer. If it gets larger than
     * a given size, we actually write to the sockets. */
    if (len) {
        r->io.fdset.buf = sdscatlen(r->io.fdset.buf,buf,len);
        len = 0; /* Prevent entering the while below if we don't flush. */
        if (sdslen(r->io.fdset.buf) > PROTO_IOBUF_LEN) doflush = 1;
    }

    if (doflush) {
        p = (unsigned char*) r->io.fdset.buf;
        len = sdslen(r->io.fdset.buf);
    }

    /* Write in little chunchs so that when there are big writes we
     * parallelize while the kernel is sending data in background to
     * the TCP socket. */
    while(len) {
        size_t count = len < 1024 ? len : 1024;
        int broken = 0;
        for (j = 0; j < r->io.fdset.numfds; j++) {
            if (r->io.fdset.state[j] != 0) {
                /* Skip FDs alraedy in error. */
                broken++;
                continue;
            }

            /* Make sure to write 'count' bytes to the socket regardless
             * of short writes. */
            size_t nwritten = 0;
            while(nwritten != count) {
                retval = write(r->io.fdset.fds[j],p+nwritten,count-nwritten);
                if (retval <= 0) {
                    /* With blocking sockets, which is the sole user of this
                     * rio target, EWOULDBLOCK is returned only because of
                     * the SO_SNDTIMEO socket option, so we translate the error
                     * into one more recognizable by the user. */
                    if (retval == -1 && errno == EWOULDBLOCK) errno = ETIMEDOUT;
                    break;
                }
                nwritten += retval;
            }

            if (nwritten != count) {
                /* Mark this FD as broken. */
                r->io.fdset.state[j] = errno;
                if (r->io.fdset.state[j] == 0) r->io.fdset.state[j] = EIO;
            }
        }
        if (broken == r->io.fdset.numfds) return 0; /* All the FDs in error. */
        p += count;
        len -= count;
        r->io.fdset.pos += count;
    }

    if (doflush) sdsclear(r->io.fdset.buf);
    return 1;
}
Example #10
0
size_t cetcd_parse_response(char *ptr, size_t size, size_t nmemb, void *userdata) {
    int len, i;
    char *key, *val;
    cetcd_response *resp;
    cetcd_response_parser *parser;
    yajl_status status;

    enum resp_parser_st {
        request_line_start_st,
        request_line_end_st,
        request_line_http_status_start_st,
        request_line_http_status_st,
        request_line_http_status_end_st,
        header_key_start_st,
        header_key_st,
        header_key_end_st,
        header_val_start_st,
        header_val_st,
        header_val_end_st,
        blank_line_st,
        json_start_st,
        json_end_st,
        response_discard_st
    };
    /* Headers we are interested in:
     * X-Etcd-Index: 14695
     * X-Raft-Index: 672930
     * X-Raft-Term: 12
     * */

    parser = userdata;
    resp = parser->resp;
    len = size * nmemb;
    for (i = 0; i < len; ++i) {
        if (parser->st == request_line_start_st) {
            if (ptr[i] == ' ') {
                parser->st = request_line_http_status_start_st;
            }
            continue;
        }
        if (parser->st == request_line_end_st) {
            if (ptr[i] == '\n') {
                parser->st = header_key_start_st;
            }
            continue;
        }
        if (parser->st == request_line_http_status_start_st) {
            parser->buf = sdscatlen(parser->buf, ptr+i, 1);
            parser->st = request_line_http_status_st;
            continue;
        }
        if (parser->st == request_line_http_status_st) {
            if (ptr[i] == ' ') {
                parser->st = request_line_http_status_end_st;
            } else {
                parser->buf = sdscatlen(parser->buf, ptr+i, 1);
                continue;
            }
        }
        if (parser->st == request_line_http_status_end_st) {
            val = parser->buf;
            parser->http_status = atoi(val);
            sdsclear(parser->buf);
            parser->st = request_line_end_st;
            continue;
        }
        if (parser->st == header_key_start_st) {
            if (ptr[i] == '\r') {
                ++i;
            }
            if (ptr[i] == '\n') {
                parser->st = blank_line_st;
                if (parser->http_status >= 300 && parser->http_status < 400) {
                    /*this is a redirection, restart the state machine*/
                    parser->st = request_line_start_st;
                    break;
                }
                continue;
            }
            parser->st = header_key_st;
        }
        if (parser->st == header_key_st) {
            parser->buf = sdscatlen(parser->buf, ptr+i, 1);
            if (ptr[i] == ':') {
                parser->st = header_key_end_st;
            } else {
                continue;
            }
        }
        if (parser->st == header_key_end_st) {
            parser->st = header_val_start_st;
            continue;
        }
        if (parser->st == header_val_start_st) {
            if (ptr[i] == ' ') {
                continue;
            }
            parser->st = header_val_st;
        }
        if (parser->st == header_val_st) {
            if (ptr[i] == '\r') {
                ++i;
            }
            if (ptr[i] == '\n') {
                parser->st = header_val_end_st;
            } else {
                parser->buf = sdscatlen(parser->buf, ptr+i, 1);
                continue;
            }
        }
        if (parser->st == header_val_end_st) {
            parser->st = header_key_start_st;
            int count = 0;
            sds *kvs = sdssplitlen(parser->buf, sdslen(parser->buf), ":", 1, &count);
            sdsclear(parser->buf);
            if (count < 2) {
                sdsfreesplitres(kvs, count);
                continue;
            }
            key = kvs[0];
            val = kvs[1];
            if (strncmp(key, "X-Etcd-Index", sizeof("X-Etcd-Index")-1) == 0) {
                resp->etcd_index = atoi(val);
            } else if (strncmp(key, "X-Raft-Index", sizeof("X-Raft-Index")-1) == 0) {
                resp->raft_index = atoi(val);
            } else if (strncmp(key, "X-Raft-Term", sizeof("X-Raft-Term")-1) == 0) {
                resp->raft_term = atoi(val);
            }
            sdsfreesplitres(kvs, count);
            continue;
        }
        if (parser->st == blank_line_st) {
            if (ptr[i] != '{') {
                /*not a json response, discard*/
                parser->st = response_discard_st;
                if (resp->err == NULL) {
                    resp->err = calloc(1, sizeof(cetcd_error));
                    resp->err->ecode = error_response_parsed_failed;
                    resp->err->message = sdsnew("not a json response");
                    resp->err->cause = sdsnewlen(ptr, len);
                }
                continue;
            }
            parser->st = json_start_st;
            cetcd_array_init(&parser->ctx.keystack, 10);
            cetcd_array_init(&parser->ctx.nodestack, 10);
            if (parser->http_status != 200 && parser->http_status != 201) {
                resp->err = calloc(1, sizeof(cetcd_error));
                parser->ctx.userdata = resp->err;
                parser->json = yajl_alloc(&error_callbacks, 0, &parser->ctx);
            } else {
                parser->ctx.userdata = resp;
                parser->json = yajl_alloc(&callbacks, 0, &parser->ctx);
            }
        }
        if (parser->st == json_start_st) {
            if (yajl_status_ok != yajl_parse(parser->json, (const unsigned char *)ptr + i, len - i)) {
                parser->st = json_end_st;
            } else {
                parser->st = response_discard_st;
                yajl_free(parser->json);
                cetcd_array_destory(&parser->ctx.keystack);
                cetcd_array_destory(&parser->ctx.nodestack);
            }
        }
        if (parser->st == json_end_st) {
            status = yajl_complete_parse(parser->json);
            yajl_free(parser->json);
            cetcd_array_destory(&parser->ctx.keystack);
            cetcd_array_destory(&parser->ctx.nodestack);
            /*parse failed, TODO set error message*/
            if (status != yajl_status_ok) {
                if (resp->err == NULL) {
                    resp->err = calloc(1, sizeof(cetcd_error));
                    resp->err->ecode = error_response_parsed_failed;
                    resp->err->message = sdsnew("http response is invalid json format");
                    resp->err->cause = sdsnewlen(ptr, len);
                }
                return 0;
            }
            break;
        }
        if (parser->st == response_discard_st) {
            return len;
        }
    }
    return len;
}
Example #11
0
static int cetcd_reap_watchers(cetcd_client *cli, CURLM *mcurl) {
    int     added, ignore;
    CURLMsg *msg;
    CURL    *curl;
    cetcd_string url;
    cetcd_watcher *watcher;
    cetcd_response *resp;
    added = 0;
    while ((msg = curl_multi_info_read(mcurl, &ignore)) != NULL) {
        if (msg->msg == CURLMSG_DONE) {
            curl = msg->easy_handle;
            curl_easy_getinfo(curl, CURLINFO_PRIVATE, &watcher);

            resp = watcher->parser->resp;
            if (msg->data.result != CURLE_OK) {
                /*try next in round-robin ways*/
                /*FIXME There is a race condition if multiple watchers failed*/
                if (watcher->attempts) {
                    cli->picked = (cli->picked+1)%(cetcd_array_size(cli->addresses));
                    url = cetcd_watcher_build_url(cli, watcher);
                    curl_easy_setopt(watcher->curl, CURLOPT_URL, url);
                    sdsfree(url);
                    curl_multi_remove_handle(mcurl, curl);
                    curl_multi_add_handle(mcurl, curl);
                    /*++added;
                     *watcher->attempts --;
                     */
                    continue;
                } else {
                    resp->err = calloc(1, sizeof(cetcd_error));
                    resp->err->ecode = error_cluster_failed;
                    resp->err->message = sdsnew("cetcd_reap_watchers: all cluster servers failed.");
                }
            }
            if (watcher->callback) {
                watcher->callback(watcher->userdata, resp);
                if (resp->err) {
                    curl_multi_remove_handle(mcurl, curl);
                    cetcd_watcher_release(watcher);
                    break;
                }
                cetcd_response_release(resp);
                watcher->parser->resp = NULL; /*surpress it be freed again by cetcd_watcher_release*/
            }
            if (!watcher->once) {
                sdsclear(watcher->parser->buf);
                watcher->parser->st = 0;
                watcher->parser->resp = calloc(1, sizeof(cetcd_response));
                if (watcher->index) {
                    watcher->index ++;
                    url = cetcd_watcher_build_url(cli, watcher);
                    curl_easy_setopt(watcher->curl, CURLOPT_URL, url);
                    sdsfree(url);
                }
                curl_multi_remove_handle(mcurl, curl);
                curl_multi_add_handle(mcurl, curl);
                ++added;
                continue;
            }
            curl_multi_remove_handle(mcurl, curl);
            cetcd_watcher_release(watcher);
        }
    }
    return added;
}
Example #12
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. */
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)) {
        /* Ooops, we are in troubles. The best thing to do for now is
         * aborting instead of giving the illusion that everything is
         * working as expected. */
        if (nwritten == -1) {
            redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
        } else {
            redisLog(REDIS_WARNING,"Exiting on short write while writing to "
                                   "the append-only file: %s (nwritten=%ld, "
                                   "expected=%ld)",
                                   strerror(errno),
                                   (long)nwritten,
                                   (long)sdslen(server.aof_buf));

            if (ftruncate(server.aof_fd, server.aof_current_size) == -1) {
                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));
            }
        }
        exit(1);
    }
    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;
    }
}
Example #13
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;
    }
}
Example #14
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 ) );
		}
	}
}
Example #15
0
/* sid = |flags(4byte)|client fd(4byte)| */
static int
smrCbData (void *arg, long long seq, long long timestamp,
	   short nid, int sid, int hash, smrData * smr_data, int size)
{
  char *data = smr_data_get_data (smr_data);
  redisClient *c;
  short cmdflags;
  dlisth *node;

  /* Special commands */
  if (size == 1 && data[0] == REDIS_SMR_CMD_CATCHUP_CHECK)
    {
      if (nid == smr_get_nid (server.smr_conn)
	  && (server.smr_init_flags & SMR_INIT_CATCHUP_PHASE2))
	checkSmrCatchup ();
      goto release_seq;
    }
  else if (size == 1 && data[0] == REDIS_SMR_CMD_DELIVER_OOM)
    {
      server.smr_oom_until = timestamp + REDIS_OOM_DURATION_MS;
      goto release_seq;
    }

  /* Normal command */
  server.smr_mstime = timestamp;
  cmdflags = (0xFFFF0000 & sid) >> 16;

  /* Because we fixed the bug that causes timestamp be 0, 
   * this warning log is not necessary and just an assert statement is enough after all.
   * But currently, there are nbase-arc clusters which have the bug.
   * So, we don't assert for now. */
  if (timestamp == 0)
    {
      redisLog (REDIS_WARNING, "Timestamp of SMR callback is 0,"
		"seq:%lld, nid:%d, sid:%d, hash:%d, size:%d",
		seq, nid, sid, hash, size);
    }

  if ((server.smr_init_flags & SMR_INIT_DONE)
      && nid == smr_get_nid (server.smr_conn))
    {
      callbackInfo *cb;
      /* query from this server. get client from global callback list */
      assert (!dlisth_is_empty (&server.global_callbacks));	/* global callback list shouldn't be empty */
      node = server.global_callbacks.next;
      cb = (callbackInfo *) node;
      dlisth_delete (&cb->global_head);
      dlisth_delete (&cb->client_head);
      c = cb->client;
      assert (cb->hash == hash);
      assert (c->fd == -1 || c->fd == (0X0000FFFF & sid));

      /* We already parsed querybuf because the query is requested from this 
       * server before smr callback*/
      c->argc = cb->argc;
      c->argv = cb->argv;
      cb->argc = 0;
      cb->argv = NULL;
      zfree (cb);

      server.current_client = c;

      /* fake client doesn't need to execute non-write query(read-only or admin) */
      if (c->fd != -1 || cmdflags & REDIS_CMD_WRITE)
	{
	  assert (!(c->flags & REDIS_CLOSE_AFTER_REPLY));
	  processCommand (c);
	}
    }
  else
    {
      /* replicated query from other servers, or catchup query during initialize */
      c = server.smrlog_client;
      server.current_client = c;

      /* fake client doesn't need to execute non-write query(read-only or admin) */
      if (cmdflags & REDIS_CMD_WRITE)
	{
	  /* We need to parse querybuf because the query is from different server 
	   * or we are recovering without client */
	  sdsclear (c->querybuf);
	  c->querybuf = sdsMakeRoomFor (c->querybuf, size);
	  memcpy (c->querybuf, data, size);
	  sdsIncrLen (c->querybuf, size);
	  if (c->querybuf_peak < size)
	    c->querybuf_peak = size;
	  processInputBuffer (c);
	}
    }

  resetClient (c);
  zfree (c->argv);
  c->argv = NULL;
  server.current_client = NULL;

release_seq:
  if (smr_release_seq_upto (server.smr_conn, seq + size) == -1)
    {
      redisLog (REDIS_WARNING, "smr_release_seq_upto error");
      redisAssert (0);
      return REDIS_ERR;
    }
  server.smr_seqnum = seq + size;

  return REDIS_OK;
}
Example #16
0
static int se_try_read(lua_State *L, int fd, int size, sds *pcache)
{
	char sbuf[4 << 10];
	char *cache = *pcache;
	char *buf;
	int bufsize;
	int nread;

	if (cache) {
		bufsize = sdsavail(cache);
		buf = cache + sdslen(cache);
		printf("continue try read: %d / %d\n", bufsize, size);
	} else { // first try
		bufsize = size > 0 ? size : size < 0 ? -size : sizeof(sbuf);
		if (bufsize <= sizeof(sbuf)) {
			buf = sbuf;
		} else {
			cache = sdsnewlen(NULL, bufsize);
			oom_check(cache);
			sdsclear(cache);
			*pcache = cache;
			buf = cache;
		}
		printf("try read: %d / %d\n", bufsize, size);
	}

	nread = read(fd, buf, bufsize);
	if (nread > 0) {
		if (size <= 0 || nread == bufsize) { // done
			if (cache) {
				lua_pushlstring(L, cache, sdslen(cache) + nread);
				sdsfree(cache);
				*pcache = NULL;
			} else {
				lua_pushlstring(L, buf, nread);
			}
			printf("read done: %d / %d / %d\n", nread, bufsize, size);
			return 1;
		}
		// partial read
		if (!cache) {
			cache = sdsnewlen(NULL, bufsize);
			oom_check(cache);
			sdsclear(cache);
			*pcache = cache;
			memcpy(cache, buf, nread);
		}
		sdsIncrLen(cache, nread);
		printf("partial read: %d / %d / %d\n", nread, bufsize, size);
		return -1;
	}

	if (nread == 0)
		return se_read_error(L, pcache, "EOF");

	if (errno == EAGAIN || errno == EWOULDBLOCK)
		return -1;

	se_assert(L, errno != EBADF, "read(%d) error", fd);
	return se_read_error(L, pcache, strerror(errno));
}