RequestProcessorResponseStatus RequestProcessor::ProcessGetStream(Envelope &request, vector<Envelope> &output) { { ::zippylog::request_processor::BeginProcessGetStream log; LOG_MESSAGE(log, this->logger_sock); } protocol::request::GetStreamSegmentV1 *get = (protocol::request::GetStreamSegmentV1 *)request.GetMessage(0); if (!get) { ::zippylog::request_processor::ReceiveInvalidGet log; LOG_MESSAGE(log, this->logger_sock); this->PopulateErrorResponse( protocol::response::UNKNOWN_REQUEST_TYPE, "error parsing get message... weird", output ); goto LOG_END; } if (!get->has_path()) { ::zippylog::request_processor::ReceiveInvalidGet log; LOG_MESSAGE(log, this->logger_sock); this->PopulateErrorResponse( protocol::response::EMPTY_FIELD, "required field 'path' is not set", output ); goto LOG_END; } if (!this->CheckPath(get->path(), output, true, true, true)) goto LOG_END; if (!get->has_start_offset()) { ::zippylog::request_processor::ReceiveInvalidGet log; LOG_MESSAGE(log, this->logger_sock); this->PopulateErrorResponse( protocol::response::EMPTY_FIELD, "required field 'start_offset' is not set", output ); goto LOG_END; } { InputStream *stream = this->store->GetInputStream(get->path()); if (!stream) { // we've already verified the stream exists, so there are one of two possibilities: // 1) it was deleted between then and now // 2) error fetching stream // @todo react accordingly ::zippylog::request_processor::GetInvalidStream log; LOG_MESSAGE(log, this->logger_sock); this->PopulateErrorResponse( protocol::response::PATH_NOT_FOUND, "requested stream could not be found", output ); goto LOG_END; } uint64 start_offset = get->start_offset(); if (start_offset && !stream->SetAbsoluteOffset(start_offset)) { throw Exception("TODO handle error setting offset properly"); } // determine how much to fetch uint32 bytes_left = this->get_stream_max_bytes; uint32 envelopes_left = this->get_stream_max_envelopes; // client can lower server default if it wants if (get->has_max_response_bytes() && get->max_response_bytes() < bytes_left) { bytes_left = get->max_response_bytes(); } if (get->has_max_response_envelopes() && get->max_response_envelopes() < envelopes_left) { envelopes_left = get->max_response_envelopes(); } zippylog::Envelope m = zippylog::Envelope(); uint32 envelope_size = stream->NextEnvelopeSize(); ::zippylog::Envelope env; // could not find envelope in stream at offset if (!envelope_size || !stream->ReadEnvelope(env, envelope_size)) { ::zippylog::request_processor::GetInvalidOffset log; LOG_MESSAGE(log, this->logger_sock); // @todo need better error code this->PopulateErrorResponse( protocol::response::INVALID_STREAM_OFFSET, "no envelopes found at requested stream offset", output ); goto LOG_END; } // we must have an envelope, so start the send sequence { Envelope start_envelope; protocol::response::StreamSegmentStartV1 segment_start; segment_start.set_path(get->path()); segment_start.set_offset(get->start_offset()); segment_start.add_to_envelope(start_envelope); // copy request tags to response for client association if (request.TagSize() >= 0) { for (int i = 0; i < request.TagSize(); i++) { start_envelope.AddTag(request.GetTag(i)); } } output.push_back(start_envelope); } output.push_back(env); uint32 bytes_read = envelope_size; uint32 envelopes_read = 1; envelopes_left--; if (bytes_read < bytes_left && envelopes_left) { bytes_left -= envelope_size; while (true) { envelope_size = stream->NextEnvelopeSize(); if (!envelope_size) break; // @todo we should be resilient and handle stream errors somehow if (!stream->ReadEnvelope(env, envelope_size)) break; output.push_back(env); bytes_read += envelope_size; envelopes_read++; if (envelope_size > bytes_left) break; if (envelopes_left-- == 1) break; bytes_left -= envelope_size; } } protocol::response::StreamSegmentEndV1 segment_end; segment_end.set_envelopes_sent(envelopes_read); segment_end.set_bytes_sent(bytes_read); // @todo not all stores might share this concept of offsets segment_end.set_offset(stream->CurrentEnvelopeOffset()); env = ::zippylog::Envelope(); segment_end.add_to_envelope(&env); output.push_back(env); } LOG_END: ::zippylog::request_processor:: EndProcessGetStream logend; LOG_MESSAGE(logend, this->logger_sock); return AUTHORITATIVE; }