blob: 35e73844de6bbcff2d0cdd7071df2bb6fa4f9f86 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_
#define SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_
#include <cstddef>
#include <optional>
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/trace_processor/trace_blob_view.h"
namespace perfetto::trace_processor::util {
// Helper class that exposes a window into the contents of a file. Data can be
// appended to the end of the buffer (increasing the size of the window) or
// removed from the front (decreasing the size of the window).
//
// TraceProcessor reads trace files in chunks and streams those to the
// `ChunkedTraceReader` instance. But sometimes the reader needs to look into
// the future (i.e. some data that has not yet arrived) before being able to
// process the current data. In such a case the reader would have to buffer data
// until the "future" data arrives. This class encapsulates that functionality.
class FileBuffer {
public:
// Trivial empty ctor.
FileBuffer() = default;
bool empty() const { return data_.empty(); }
// Returns the offset to the start of the buffered window of data.
size_t file_offset() const {
return data_.empty() ? end_offset_ : data_.front().file_offset;
}
// Adds a `TraceBlobView` at the back.
void PushBack(TraceBlobView view);
// Shrinks the buffer by dropping data from the front of the buffer until the
// given offset is reached. If not enough data is present as much data as
// possible will be dropped and `false` will be returned.
// ATTENTION: If `offset` < 'file_offset()' (i.e. you try to access data
// previously popped) this method will CHECK fail.
bool PopFrontUntil(size_t offset);
// Shrinks the buffer by dropping `bytes` from the front of the buffer. If not
// enough data is present as much data as possible will be dropped and `false`
// will be returned.
bool PopFrontBytes(size_t bytes) {
return PopFrontUntil(file_offset() + bytes);
}
// Similar to `TraceBlobView::slice_off`, creates a slice with data starting
// at `offset` and of the given `length`. This method might need to allocate a
// new buffer and copy data into it (if the requested data spans multiple
// TraceBlobView instances). If not enough data is present `std::nullopt` is
// returned.
//
// ATTENTION: If `offset` < 'file_offset()' (i.e. you try to access data
// previously popped) this method will CHECK fail.
std::optional<TraceBlobView> SliceOff(size_t offset, size_t length) const;
private:
struct Entry {
// File offset of the first byte in `data`.
size_t file_offset;
TraceBlobView data;
};
using Iterator = base::CircularQueue<Entry>::Iterator;
// Finds the `TraceBlobView` at `offset` and returns a slice starting at that
// offset and spanning the rest of the `TraceBlobView`. It also returns an
// iterator to the next `TraceBlobView` instance (which might be `end()`).
Iterator FindEntryWithOffset(size_t offset) const;
Iterator end() const { return data_.end(); }
// CircularQueue has no const_iterator, so mutable is needed to access it from
// const methods.
// CircularQueue has no const_iterator, so mutable is needed to access it from
// const methods.
mutable base::CircularQueue<Entry> data_;
size_t end_offset_ = 0;
};
} // namespace perfetto::trace_processor::util
#endif // SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_