Exemple #1
0
void Connection::PendingWriteBase::on_write(uv_write_t* req, int status) {
  PendingWrite* pending_write = static_cast<PendingWrite*>(req->data);

  Connection* connection = static_cast<Connection*>(pending_write->connection_);

  while (!pending_write->handlers_.is_empty()) {
    Handler* handler = pending_write->handlers_.front();

    pending_write->handlers_.remove(handler);

    switch (handler->state()) {
      case Handler::REQUEST_STATE_WRITING:
        if (status == 0) {
          handler->set_state(Handler::REQUEST_STATE_READING);
          connection->pending_reads_.add_to_back(handler);
        } else {
          if (!connection->is_closing()) {
            connection->notify_error("Write error '" +
                                     std::string(UV_ERRSTR(status, connection->loop_)) +
                                     "'");
            connection->defunct();
          }

          connection->stream_manager_.release(handler->stream());
          handler->stop_timer();
          handler->set_state(Handler::REQUEST_STATE_DONE);
          handler->on_error(CASS_ERROR_LIB_WRITE_ERROR,
                            "Unable to write to socket");
          handler->dec_ref();
        }
        break;

      case Handler::REQUEST_STATE_TIMEOUT_WRITE_OUTSTANDING:
        // The read may still come back, handle cleanup there
        handler->set_state(Handler::REQUEST_STATE_TIMEOUT);
        connection->pending_reads_.add_to_back(handler);
        break;

      case Handler::REQUEST_STATE_READ_BEFORE_WRITE:
        // The read callback happened before the write callback
        // returned. This is now responsible for cleanup.
        handler->stop_timer();
        handler->set_state(Handler::REQUEST_STATE_DONE);
        handler->dec_ref();
        break;

      case Handler::REQUEST_STATE_RETRY_WRITE_OUTSTANDING:
        handler->stop_timer();
        handler->retry();
        handler->dec_ref();
        break;

      default:
        assert(false && "Invalid request state after write finished");
        break;
    }
  }

  connection->pending_writes_size_ -= pending_write->size();
  if (connection->pending_writes_size_ <
      connection->config_.write_bytes_low_water_mark() &&
      connection->state_ == CONNECTION_STATE_OVERWHELMED) {
    connection->set_state(CONNECTION_STATE_READY);
  }

  connection->pending_writes_.remove(pending_write);
  delete pending_write;

  connection->flush();
}
Exemple #2
0
void Connection::consume(char* input, size_t size) {
  char* buffer = input;
  size_t remaining = size;

  // A successful read means the connection is still responsive
  restart_terminate_timer();

  while (remaining != 0) {
    ssize_t consumed = response_->decode(buffer, remaining);
    if (consumed <= 0) {
      notify_error("Error consuming message");
      remaining = 0;
      continue;
    }

    if (response_->is_body_ready()) {
      ScopedPtr<ResponseMessage> response(response_.release());
      response_.reset(new ResponseMessage());

      LOG_TRACE("Consumed message type %s with stream %d, input %u, remaining %u on host %s",
                opcode_to_string(response->opcode()).c_str(),
                static_cast<int>(response->stream()),
                static_cast<unsigned int>(size),
                static_cast<unsigned int>(remaining),
                host_->address_string().c_str());

      if (response->stream() < 0) {
        if (response->opcode() == CQL_OPCODE_EVENT) {
          listener_->on_event(static_cast<EventResponse*>(response->response_body().get()));
        } else {
          notify_error("Invalid response opcode for event stream: " +
                       opcode_to_string(response->opcode()));
        }
      } else {
        Handler* handler = NULL;
        if (stream_manager_.get_pending_and_release(response->stream(), handler)) {
          switch (handler->state()) {
            case Handler::REQUEST_STATE_READING:
              maybe_set_keyspace(response.get());
              pending_reads_.remove(handler);
              handler->stop_timer();
              handler->set_state(Handler::REQUEST_STATE_DONE);
              handler->on_set(response.get());
              handler->dec_ref();
              break;

            case Handler::REQUEST_STATE_WRITING:
              // There are cases when the read callback will happen
              // before the write callback. If this happens we have
              // to allow the write callback to cleanup.
              maybe_set_keyspace(response.get());
              handler->set_state(Handler::REQUEST_STATE_READ_BEFORE_WRITE);
              handler->on_set(response.get());
              break;

            case Handler::REQUEST_STATE_TIMEOUT:
              pending_reads_.remove(handler);
              handler->set_state(Handler::REQUEST_STATE_DONE);
              handler->dec_ref();
              break;

            case Handler::REQUEST_STATE_TIMEOUT_WRITE_OUTSTANDING:
              // We must wait for the write callback before we can do the cleanup
              handler->set_state(Handler::REQUEST_STATE_READ_BEFORE_WRITE);
              break;

            default:
              assert(false && "Invalid request state after receiving response");
              break;
          }
        } else {
          notify_error("Invalid stream ID");
        }
      }
    }
    remaining -= consumed;
    buffer += consumed;
  }
}