Index: webrtc/base/stream.cc |
diff --git a/webrtc/base/stream.cc b/webrtc/base/stream.cc |
index e22c3d8aa4ef567ea656183cedb500af5623a539..3e3afa040dae9e0bf75531bc39f28a18acabaffe 100644 |
--- a/webrtc/base/stream.cc |
+++ b/webrtc/base/stream.cc |
@@ -517,6 +517,113 @@ void FileStream::DoClose() { |
fclose(file_); |
} |
+CircularFileStream::CircularFileStream(size_t max_size) |
+ : max_write_size_(max_size), |
+ position_(0), |
+ marked_position_(max_size / 2), |
+ last_write_position_(0), |
+ read_segment_(READ_LATEST), |
+ read_segment_available_(0) { |
+} |
+ |
+bool CircularFileStream::Open(const std::string& filename, |
+ const char* mode, |
+ int* error) { |
+ if (!FileStream::Open(filename.c_str(), mode, error)) |
+ return false; |
+ |
+ if (strchr(mode, "r") != NULL) { // Opened in read mode. |
+ // Check if the buffer has been overwritten and determine how to read the |
+ // log in time sequence. |
+ size_t file_size; |
+ GetSize(&file_size); |
+ if (file_size == position_) { |
+ // The buffer has not been overwritten yet. Read 0 .. file_size |
+ read_segment_ = READ_LATEST; |
+ read_segment_available_ = file_size; |
+ } else { |
+ // The buffer has been over written. There are three segments: The first |
+ // one is 0 .. marked_position_, which is the marked earliest log. The |
+ // second one is position_ .. file_size, which is the middle log. The |
+ // last one is marked_position_ .. position_, which is the latest log. |
+ read_segment_ = READ_MARKED; |
+ read_segment_available_ = marked_position_; |
+ last_write_position_ = position_; |
+ } |
+ |
+ // Read from the beginning. |
+ position_ = 0; |
+ SetPosition(position_); |
+ } |
+ |
+ return true; |
+} |
+ |
+StreamResult CircularFileStream::Read(void* buffer, |
+ size_t buffer_len, |
+ size_t* read, |
+ int* error) { |
+ if (read_segment_available_ == 0) { |
+ size_t file_size; |
+ switch (read_segment_) { |
+ case READ_MARKED: // Finished READ_MARKED and start READ_MIDDLE. |
+ read_segment_ = READ_MIDDLE; |
+ position_ = last_write_position_; |
+ SetPosition(position_); |
+ GetSize(&file_size); |
+ read_segment_available_ = file_size - position_; |
+ break; |
+ |
+ case READ_MIDDLE: // Finished READ_MIDDLE and start READ_LATEST. |
+ read_segment_ = READ_LATEST; |
+ position_ = marked_position_; |
+ SetPosition(position_); |
+ read_segment_available_ = last_write_position_ - position_; |
+ break; |
+ |
+ default: // Finished READ_LATEST and return EOS. |
+ return rtc::SR_EOS; |
+ } |
+ } |
+ |
+ size_t local_read; |
+ if (!read) |
+ read = &local_read; |
+ |
+ size_t to_read = std::min(buffer_len, read_segment_available_); |
+ rtc::StreamResult result = |
+ rtc::FileStream::Read(buffer, to_read, read, error); |
+ if (result == rtc::SR_SUCCESS) { |
+ read_segment_available_ -= *read; |
+ position_ += *read; |
+ } |
+ return result; |
+} |
+ |
+StreamResult CircularFileStream::Write(const void* data, |
+ size_t data_len, |
+ size_t* written, |
+ int* error) { |
+ if (position_ >= max_write_size_) { |
+ ASSERT(position_ == max_write_size_); |
+ position_ = marked_position_; |
+ SetPosition(position_); |
+ } |
+ |
+ size_t local_written; |
+ if (!written) |
+ written = &local_written; |
+ |
+ size_t to_eof = max_write_size_ - position_; |
+ size_t to_write = std::min(data_len, to_eof); |
+ rtc::StreamResult result = |
+ rtc::FileStream::Write(data, to_write, written, error); |
+ if (result == rtc::SR_SUCCESS) { |
+ position_ += *written; |
+ } |
+ return result; |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
// MemoryStream |
/////////////////////////////////////////////////////////////////////////////// |