blob: 42e5b442932763ef7e5a23401764c944d25e67d0 [file] [log] [blame]
// 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.
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
namespace ureadahead_diff {
// Constants and definitions from ureadhead/src/pack.*
#define PACK_PATH_MAX 255
enum PackFlags {
// Keep it as declared in pack.h. Default alignment must be used.
struct PackPath {
int group;
ino_t ino;
char path[PACK_PATH_MAX + 1];
bool operator==(const PackPath& other) const;
bool operator!=(const PackPath& other) const;
// Keep it as declared in pack.h. Default alignment must be used.
struct PackBlock {
size_t pathidx;
off_t offset;
off_t length;
off_t physical;
bool operator==(const PackBlock& other) const;
bool operator!=(const PackBlock& other) const;
// Represents individual file in ureadahead pack file.
class FileEntry {
explicit FileEntry(const PackPath& pack_path);
FileEntry(const FileEntry&) = delete;
FileEntry& operator=(const FileEntry&) = delete;
// Builds |FileEntry| based on provided read requests. Each request is
// std::pair of offset and length of the each read operation.
void BuildFromReadRequests(const std::vector<PackBlock>& read_requests);
// Returns read request that is calculated from |read_map_|. |pathidx|
// specifies the global index for this file.
std::vector<PackBlock> GetReadRequests(size_t pathidx) const;
// Returns true if file does not have any read block.
bool IsEmpty() const;
// Calculates difference of two files. It puts the common part into |common|
// and leaves difference in |file1| and |file2] correspondingly. Note, that
// sizes of read requests might be different and |common| will have the size
// of minimum of read requests sizes of |file1| and |file2|.
static void CalculateDifference(FileEntry* file1,
FileEntry* file2,
FileEntry* common);
const PackPath& pack_path() const { return pack_path_; }
using ReadMap = std::vector<bool>;
const PackPath pack_path_;
// Each bit in the collections corresponds one page of file.
ReadMap read_map_;
// Represents ureadahead pack.
class Pack {
// Source pack specifies the source pack and output specifies pack that
// contains difference.
Pack(const Pack&) = delete;
Pack& operator=(const Pack&) = delete;
// Returns the number of files in the pack.
size_t GetFileCount() const;
// Returns file by index.
FileEntry* GetFile(size_t index);
// Adds file to the pack.
void AddFile(std::unique_ptr<FileEntry> file);
// Finds the file in this pack that corresponds to the provided |other_file|
// which may belong to the different pack. Returns nullptr if match is not
// found.
FileEntry* FindFile(FileEntry* other_file);
// Reads ureadahead pack from |path|.
bool Read(const std::string& path);
// Writes pack to the |path|.
bool Write(const std::string& path) const;
// Removes all files that do not have read operations.
void TrimEmptyFiles();
// Calculates difference of two packs. It puts the common part into |common|
// and leaves difference in |pack1| and |pack2] correspondingly.
static void CalculateDifference(Pack* pack1, Pack* pack2, Pack* common);
bool Read(int fd);
bool Write(int fd) const;
// Mapped from ureadahead's struct pack_file.
dev_t dev_ = 0;
std::vector<std::unique_ptr<FileEntry>> files_;
} // namespace ureadahead_diff