Add method to encode a batch of RtcEvents.

Bug: webrtc:8111
Change-Id: Ieb3ff6b817a6bc068b358d49e6d6df07e3ec8d8b
Reviewed-on: https://webrtc-review.googlesource.com/32720
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Elad Alon <eladalon@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21286}
This commit is contained in:
Bjorn Terelius 2017-12-14 19:06:41 +01:00 committed by Commit Bot
parent a32d710bb4
commit 5cab6f1dc7
4 changed files with 60 additions and 84 deletions

View File

@ -11,6 +11,8 @@
#ifndef LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_H_
#include <deque>
#include <memory>
#include <string>
#include "logging/rtc_event_log/events/rtc_event.h"
@ -21,6 +23,10 @@ class RtcEventLogEncoder {
virtual ~RtcEventLogEncoder() = default;
virtual std::string Encode(const RtcEvent& event) = 0;
virtual std::string EncodeBatch(
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) = 0;
};
} // namespace webrtc

View File

@ -107,6 +107,18 @@ rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) {
}
} // namespace
std::string RtcEventLogEncoderLegacy::EncodeBatch(
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) {
std::string encoded_output;
for (auto it = begin; it != end; ++it) {
// TODO(terelius): Can we avoid the slight inefficiency of reallocating the
// string?
encoded_output += Encode(**it);
}
return encoded_output;
}
std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) {
switch (event.GetType()) {
case RtcEvent::Type::AudioNetworkAdaptation: {

View File

@ -11,6 +11,7 @@
#ifndef LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
#define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_LEGACY_H_
#include <deque>
#include <memory>
#include <string>
@ -51,6 +52,10 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder {
std::string Encode(const RtcEvent& event) override;
std::string EncodeBatch(
std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin,
std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override;
private:
// Encoding entry-point for the various RtcEvent subclasses.
std::string EncodeAlrState(const RtcEventAlrState& event);

View File

@ -95,22 +95,14 @@ class RtcEventLogImpl final : public RtcEventLog {
void Log(std::unique_ptr<RtcEvent> event) override;
private:
// Appends an event to the output protobuf string, returning true on success.
// Fails and returns false in case the limit on output size prevents the
// event from being added; in this case, the output string is left unchanged.
// The event is encoded before being appended.
// We could have avoided this, because the output repeats the check, but this
// way, we minimize the number of lock acquisitions, task switches, etc.,
// that might be associated with each call to RtcEventLogOutput::Write().
bool AppendEventToString(const RtcEvent& event,
std::string* output_string) RTC_WARN_UNUSED_RESULT;
void LogToMemory(std::unique_ptr<RtcEvent> event) RTC_RUN_ON(&task_queue_);
void LogEventsFromMemoryToOutput() RTC_RUN_ON(&task_queue_);
void LogToOutput(std::unique_ptr<RtcEvent> event) RTC_RUN_ON(&task_queue_);
void StopOutput() RTC_RUN_ON(&task_queue_);
void WriteConfigsAndHistoryToOutput(const std::string& encoded_configs,
const std::string& encoded_history)
RTC_RUN_ON(&task_queue_);
void WriteToOutput(const std::string& output_string) RTC_RUN_ON(&task_queue_);
void StopLoggingInternal() RTC_RUN_ON(&task_queue_);
@ -196,7 +188,7 @@ bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output,
RTC_DCHECK(output->IsActive());
event_output_ = std::move(output);
num_config_events_written_ = 0;
LogToOutput(rtc::MakeUnique<RtcEventLoggingStarted>(start_event));
WriteToOutput(event_encoder_->Encode(start_event));
LogEventsFromMemoryToOutput();
};
@ -279,26 +271,6 @@ void RtcEventLogImpl::ScheduleOutput() {
}
}
bool RtcEventLogImpl::AppendEventToString(const RtcEvent& event,
std::string* output_string) {
RTC_DCHECK_RUN_ON(&task_queue_);
std::string encoded_event = event_encoder_->Encode(event);
bool appended;
size_t potential_new_size =
written_bytes_ + output_string->size() + encoded_event.length();
if (potential_new_size <= max_size_bytes_) {
// TODO(eladalon): This is inefficient; fix this in a separate CL.
*output_string += encoded_event;
appended = true;
} else {
appended = false;
}
return appended;
}
void RtcEventLogImpl::LogToMemory(std::unique_ptr<RtcEvent> event) {
std::deque<std::unique_ptr<RtcEvent>>& container =
event->IsConfigEvent() ? config_history_ : history_;
@ -316,65 +288,46 @@ void RtcEventLogImpl::LogEventsFromMemoryToOutput() {
RTC_DCHECK(event_output_ && event_output_->IsActive());
last_output_ms_ = rtc::TimeMillis();
std::string output_string;
// Serialize all stream configurations that haven't already been written to
// this output. |num_config_events_written_| is used to track which configs we
// have already written. (Note that the config may have been written to
// previous outputs; configs are not discarded.)
bool appended = true;
while (num_config_events_written_ < config_history_.size()) {
appended = AppendEventToString(*config_history_[num_config_events_written_],
&output_string);
if (!appended)
break;
++num_config_events_written_;
std::string encoded_configs;
RTC_DCHECK_LE(num_config_events_written_, config_history_.size());
if (num_config_events_written_ < config_history_.size()) {
const auto begin = config_history_.begin() + num_config_events_written_;
const auto end = config_history_.end();
encoded_configs = event_encoder_->EncodeBatch(begin, end);
num_config_events_written_ = config_history_.size();
}
// Serialize the events in the event queue.
while (appended && !history_.empty()) {
appended = AppendEventToString(*history_.front(), &output_string);
if (appended) {
// Known issue - if writing to the output fails, these events will have
// been lost. If we try to open a new output, these events will be missing
// from it.
history_.pop_front();
}
}
// Serialize the events in the event queue. Note that the write may fail,
// for example if we are writing to a file and have reached the maximum limit.
// We don't get any feedback if this happens, so we still remove the events
// from the event log history. This is normally not a problem, but if another
// log is started immediately after the first one becomes full, then one
// cannot rely on the second log to contain everything that isn't in the first
// log; one batch of events might be missing.
std::string encoded_history =
event_encoder_->EncodeBatch(history_.begin(), history_.end());
history_.clear();
WriteToOutput(output_string);
if (!appended) {
// Successful partial write to the output. Some events could not be written;
// the output should be closed, to avoid gaps.
StopOutput();
}
WriteConfigsAndHistoryToOutput(encoded_configs, encoded_history);
}
void RtcEventLogImpl::LogToOutput(std::unique_ptr<RtcEvent> event) {
RTC_DCHECK(event_output_ && event_output_->IsActive());
std::string output_string;
bool appended = AppendEventToString(*event, &output_string);
if (event->IsConfigEvent()) {
// Config events need to be kept in memory too, so that they may be
// rewritten into future outputs, too.
config_history_.push_back(std::move(event));
void RtcEventLogImpl::WriteConfigsAndHistoryToOutput(
const std::string& encoded_configs,
const std::string& encoded_history) {
// This function is used to merge the strings instead of calling the output
// object twice with small strings. The function also avoids copying any
// strings in the typical case where there are no config events.
if (encoded_configs.size() == 0) {
WriteToOutput(encoded_history); // Typical case.
} else if (encoded_history.size() == 0) {
WriteToOutput(encoded_configs); // Very unusual case.
} else {
WriteToOutput(encoded_configs + encoded_history);
}
if (!appended) {
if (!event->IsConfigEvent()) {
// This event will not fit into the output; push it into |history_|
// instead, so that it might be logged into the next output (if any).
history_.push_back(std::move(event));
}
StopOutput();
return;
}
WriteToOutput(output_string);
}
void RtcEventLogImpl::StopOutput() {
@ -386,8 +339,8 @@ void RtcEventLogImpl::StopOutput() {
void RtcEventLogImpl::StopLoggingInternal() {
if (event_output_) {
RTC_DCHECK(event_output_->IsActive());
event_output_->Write(
event_encoder_->Encode(*rtc::MakeUnique<RtcEventLoggingStopped>()));
RtcEventLoggingStopped stop_event;
event_output_->Write(event_encoder_->Encode(stop_event));
}
StopOutput();
}