コード例 #1
0
ファイル: t_list.c プロジェクト: aditya/redis
/* Unblock a client that's waiting in a blocking operation such as BLPOP */
void unblockClientWaitingData(redisClient *c) {
    dictEntry *de;
    list *l;
    int j;

    redisAssert(c->blocking_keys != NULL);
    /* The client may wait for multiple keys, so unblock it for every key. */
    for (j = 0; j < c->blocking_keys_num; j++) {
        /* Remove this client from the list of clients waiting for this key. */
        de = dictFind(c->db->blocking_keys,c->blocking_keys[j]);
        redisAssert(de != NULL);
        l = dictGetEntryVal(de);
        listDelNode(l,listSearchKey(l,c));
        /* If the list is empty we need to remove it to avoid wasting memory */
        if (listLength(l) == 0)
            dictDelete(c->db->blocking_keys,c->blocking_keys[j]);
        decrRefCount(c->blocking_keys[j]);
    }
    /* Cleanup the client structure */
    zfree(c->blocking_keys);
    c->blocking_keys = NULL;
    c->flags &= (~REDIS_BLOCKED);
    server.blpop_blocked_clients--;
    /* We want to process data if there is some command waiting
     * in the input buffer. Note that this is safe even if
     * unblockClientWaitingData() gets called from freeClient() because
     * freeClient() will be smart enough to call this function
     * *after* c->querybuf was set to NULL. */
    if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c);
}
コード例 #2
0
ファイル: networking.c プロジェクト: bcg/redis
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
    redisClient *c = (redisClient*) privdata;
    char buf[REDIS_IOBUF_LEN];
    int nread;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(mask);

    nread = read(fd, buf, REDIS_IOBUF_LEN);
    if (nread == -1) {
        if (errno == EAGAIN) {
            nread = 0;
        } else {
            redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
            freeClient(c);
            return;
        }
    } else if (nread == 0) {
        redisLog(REDIS_VERBOSE, "Client closed connection");
        freeClient(c);
        return;
    }
    if (nread) {
        c->querybuf = sdscatlen(c->querybuf, buf, nread);
        c->lastinteraction = time(NULL);
    } else {
        return;
    }
    processInputBuffer(c);
}
コード例 #3
0
ファイル: networking.c プロジェクト: icoulter/workspace_tubii
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
    client *c = (client*) privdata;
    int nread, readlen;
    size_t qblen;
    UNUSED(el);
    UNUSED(mask);

    readlen = PROTO_IOBUF_LEN;
    /* 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->reqtype == PROTO_REQ_MULTIBULK && c->multibulklen && c->bulklen != -1
        && c->bulklen >= PROTO_MBULK_BIG_ARG)
    {
        int remaining = (unsigned)(c->bulklen+2)-sdslen(c->querybuf);

        if (remaining < readlen) readlen = remaining;
    }

    qblen = sdslen(c->querybuf);
    if (c->querybuf_peak < qblen) c->querybuf_peak = qblen;
    c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);
    nread = read(fd, c->querybuf+qblen, readlen);
    if (nread == -1) {
        if (errno == EAGAIN) {
            return;
        } else {
            Log(LL_VERBOSE, "Reading from client: %s",strerror(errno));
            freeClient(c);
            return;
        }
    } else if (nread == 0) {
        Log(LL_VERBOSE, "Client closed connection");
        freeClient(c);
        return;
    }

    sdsIncrLen(c->querybuf,nread);
    c->lastinteraction = server.unixtime;
    server.stat_net_input_bytes += nread;
    if (sdslen(c->querybuf) > server.client_max_querybuf_len) {
        sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty();

        bytes = sdscatrepr(bytes,c->querybuf,64);
        Log(LL_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes);
        sdsfree(ci);
        sdsfree(bytes);
        freeClient(c);
        return;
    }
    processInputBuffer(c);
}
コード例 #4
0
ファイル: client.c プロジェクト: ChellsChen/wind
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);
}
コード例 #5
0
/* This function is called in the beforeSleep() function of the event loop
 * in order to process the pending input buffer of clients that were
 * unblocked after a blocking operation.
 * 取消所有在 unblocked_clients 链表中的客户端的阻塞状态
 *  */
void processUnblockedClients(void) {
    listNode *ln;
    redisClient *c;

    while (listLength(server.unblocked_clients)) {
        ln = listFirst(server.unblocked_clients);
        redisAssert(ln != NULL);
        c = ln->value;
        listDelNode(server.unblocked_clients,ln);
        c->flags &= ~REDIS_UNBLOCKED;
        c->btype = REDIS_BLOCKED_NONE;

        /* Process remaining data in the input buffer. */
        if (c->querybuf && sdslen(c->querybuf) > 0) {
            server.current_client = c;
            processInputBuffer(c);
            server.current_client = NULL;
        }
    }
}
コード例 #6
0
ファイル: blocked.c プロジェクト: xiaowei0516/redis_comment
/* This function is called in the beforeSleep() function of the event loop
 * in order to process the pending input buffer of clients that were
 * unblocked after a blocking operation. */
void processUnblockedClients(void) {
    listNode *ln;
    client *c;

    while (listLength(server.unblocked_clients)) {
        ln = listFirst(server.unblocked_clients);
        serverAssert(ln != NULL);
        c = ln->value;
        listDelNode(server.unblocked_clients,ln);
        c->flags &= ~CLIENT_UNBLOCKED;

        /* Process remaining data in the input buffer, unless the client
         * is blocked again. Actually processInputBuffer() checks that the
         * client is not blocked before to proceed, but things may change and
         * the code is conceptually more correct this way. */
        if (!(c->flags & CLIENT_BLOCKED)) {
            if (c->querybuf && sdslen(c->querybuf) > 0) {
                processInputBuffer(c);
            }
        }
    }
}
コード例 #7
0
ファイル: blocked.c プロジェクト: atomx/discnt
/* This function is called in the beforeSleep() function of the event loop
 * in order to process the pending input buffer of clients that were
 * unblocked after a blocking operation. */
void processUnblockedClients(void) {
    listNode *ln;
    client *c;

    while (listLength(server.unblocked_clients)) {
        ln = listFirst(server.unblocked_clients);
        serverAssert(ln != NULL);
        c = ln->value;
        listDelNode(server.unblocked_clients,ln);
        c->flags &= ~CLIENT_UNBLOCKED;
        /* Note that the client may be blocked again at this point, since
         * a new blocking command was processed. In that case we just remove
         * it from the unblocked clients list without actually processing
         * its pending query buffer. */
        if (!(c->flags & CLIENT_BLOCKED)) {
            c->btype = BLOCKED_NONE;

            /* Process remaining data in the input buffer. */
            if (c->querybuf && sdslen(c->querybuf) > 0) {
                processInputBuffer(c);
            }
        }
    }
}
コード例 #8
0
ファイル: redis-arc.c プロジェクト: egaoneko/nbase-arc
/* 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;
}
コード例 #9
0
void readFromMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
	REDIS_NOTUSED(el);
	REDIS_NOTUSED(mask);
	int nread;
	char rdata[MAX_READ];
	char *p = rdata;
	switch(state){
		case SYNC_START_STATE:{	 
			while(1){
				nread = readData(el, fd, p,1);
				if(nread < 0){
					return;
				}
				else if(nread == 0){
					continue;
				}
	
				int wr = writeData(el, client_fd, p, 1);
				if(-1 == wr)
				{
					return;
				}
				if(*p == '\n' && p != rdata) break;
				if(*p != '\n') p++;
			}
			*p = '\0';
			if(rdata[0] == '-'){
				log4c_category_log(mycat, LOG4C_PRIORITY_ERROR, "sync with master failed at line %d in file %s",   __LINE__, __FILE__);
				exit(1);
			}
			bulk_size = strtoull(rdata + 1, 0, 10);
			log4c_category_log(mycat, LOG4C_PRIORITY_INFO, "bulk size %llu, at line %d in file %s",  bulk_size,  __LINE__, __FILE__);
			state = SYNC_STATE;
			break;
		} 
		case SYNC_STATE:{ 
			long long int all_read =0;
			long long int all_write =0;
			while(bulk_size){
				nread = readData(el, fd, rdata, (bulk_size > MAX_READ) ? MAX_READ:bulk_size);
				if(nread < 0 )
				{
					return;
				}
				else if (nread == 0){
					continue;
				}
				else{
					all_read += nread;
				}
				int wr = writeData(el, client_fd, rdata,nread);
				if(-1 == wr)
				{
					log4c_category_log(mycat, LOG4C_PRIORITY_ERROR, "write to payload failed error %d, at line %d in file %s",  errno,  __LINE__, __FILE__);
					return;
				}
				else{
					all_write += wr;
				}
				bulk_size -= nread;
			}
			state = RUNNING_STATE;		
			log4c_category_log(mycat, LOG4C_PRIORITY_INFO, "sync done");
			break;
		} 
		default:{ 
			nread = readData(el, fd, rdata, MAX_READ);
			if(nread > 0){
				struct WData wdata;
				wdata.len = nread;
				wdata.data= rdata; 
				if( state == RUNNING_STATE){
					processInputBuffer(el, &wdata);
					int wr = writeData(el, client_fd, wdata.data, wdata.len);
					if(-1 == wr)
					{
						return;
					}
				}
				else{
					if(nread > 9 && nread < 100)
					{
						if(!strncmp(rdata,"+CONTINUE",9) || !strncmp(rdata,"+FULLRESYNC",11)){
		
							log4c_category_log(mycat, LOG4C_PRIORITY_INFO, "sync start");
							state = SYNC_START_STATE;
						}
					}
					int wr = writeData(el, client_fd, wdata.data, wdata.len);
					if(-1 == wr)
					{
						return;
					}
		
				}
			}
			break; 
		} 
	}

	
}
コード例 #10
0
ファイル: local_proxy.c プロジェクト: naver/nbase-arc
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;
}