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; }
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); }
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); }
/* 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; }
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); }
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; }
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; }
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); }
/* 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; }
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; }
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; }
/* 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; } }
/* 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; } }
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 ) ); } } }
/* 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; }
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)); }