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(); }
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; } }