| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CROSLOG_FILE_MAP_READER_H_ |
| #define CROSLOG_FILE_MAP_READER_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/memory_mapped_file.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/observer_list_types.h" |
| |
| #include "croslog/file_change_watcher.h" |
| #include "croslog/log_entry.h" |
| #include "croslog/log_parser.h" |
| |
| namespace croslog { |
| |
| class FileMapReaderDelegate; |
| |
| // A class to read a large file with chunks. |
| // How to use: |
| // - Call CreateReader(base::File) method to instantiate the class |
| // - Call MapBuffer(pos, len) method to map the specified region from the file |
| // - Use the methods of MappedBuffer class to access the content of the file. |
| // Requisites: |
| // - This class assumes the file is written with "append-only" mode and is never |
| // truncated or shrunk. If the file size shrinks, the crash may happen. |
| // (file rotation is not a problem because the renamed old log keeps its FD.) |
| class FileMapReader { |
| public: |
| // A class to access to the mapped buffer. Access to buffer should be done |
| // through this class and be safe during the lifetime of the instance. |
| class MappedBuffer { |
| public: |
| ~MappedBuffer(); |
| |
| // Returns the specified range of the buffer. The caller must be sure that |
| // the specified range is within the range passed to MapBuffer(). |
| std::pair<const uint8_t*, uint64_t> GetBuffer( |
| uint64_t request_pos, uint64_t request_length) const; |
| |
| // Returns the character (byte) at the specified position. |
| // This is inline since this is frequently called. |
| inline uint8_t GetChar(uint64_t position) const { |
| DCHECK(valid()); |
| DCHECK(buffer_start_ <= position); |
| DCHECK(position < (buffer_start_ + buffer_length_)); |
| return buffer_[position - buffer_start_]; |
| } |
| |
| // Returns true if the mmap succeeded and the mapped buffer is valid. |
| bool valid() const { return buffer_ != nullptr; } |
| |
| private: |
| friend class FileMapReader; |
| |
| MappedBuffer(const uint8_t* buffer_, |
| uint64_t buffer_start_, |
| uint64_t buffer_length_); |
| MappedBuffer(const MappedBuffer&) = delete; |
| MappedBuffer& operator=(const MappedBuffer&) = delete; |
| |
| const uint8_t* const buffer_ = nullptr; |
| const uint64_t buffer_start_ = 0; |
| const uint64_t buffer_length_ = 0; |
| |
| base::WeakPtrFactory<MappedBuffer> weak_factory_{this}; |
| }; |
| |
| // Creates an instance and returns it. |
| static std::unique_ptr<FileMapReader> CreateReader(base::File file); |
| |
| // Retrieves the chunk size. The value may change on tests. |
| static uint64_t GetChunkSizeInBytes(); |
| |
| // Static methods for test: |
| static std::unique_ptr<FileMapReader> |
| CreateFileMapReaderDelegateImplMemoryReaderForTest(const uint8_t* buffer, |
| uint64_t length); |
| static void SetBlockSizesForTest(uint64_t chunk_size_in_bytes, |
| uint32_t allocate_chunks); |
| |
| // ctor and dtor |
| explicit FileMapReader(std::unique_ptr<FileMapReaderDelegate> delegate); |
| FileMapReader(const FileMapReader&) = delete; |
| FileMapReader& operator=(const FileMapReader&) = delete; |
| |
| ~FileMapReader(); |
| |
| // Should be called when the file size is expanded. |
| void ApplyFileSizeExpansion(); |
| |
| // Maps the specified range of the buffer from the file. The mapped buffer |
| // can be accessed using the returned object. |
| // Only one MappedBuffer instance can be alive at the same time due to the |
| // current implementation limitation. Please ensure that the previous one was |
| // freed before calling this. |
| // On failure of mmap, the returned mapped buffer is invalid. |
| std::unique_ptr<MappedBuffer> MapBuffer(uint64_t request_pos, |
| uint64_t request_length); |
| |
| // Returns the cached file size of the target file. The cache is updated |
| // when RequestRemap() is called. |
| inline int64_t GetFileSize() const { |
| DCHECK_GE(file_size_, 0); |
| return file_size_; |
| } |
| |
| private: |
| // Utility method to create a mapped buffer. |
| std::unique_ptr<FileMapReader::MappedBuffer> CreateMappedBuffer(); |
| |
| // Delegate to actually map a buffer of file (or memory). |
| std::unique_ptr<FileMapReaderDelegate> delegate_; |
| |
| const uint8_t* buffer_ = nullptr; |
| uint64_t buffer_start_ = 0; |
| uint64_t buffer_length_ = 0; |
| int64_t file_size_; |
| |
| base::WeakPtr<MappedBuffer> instantiated_mapped_buffer_; |
| }; |
| |
| } // namespace croslog |
| |
| #endif // CROSLOG_FILE_MAP_READER_H_ |