#pragma once #include "query.hpp" #include namespace wl { struct Entry { uint64_t id = 0, parent = 0, size = 0, modified = 0, created = 0, accessed = 0; uint32_t attributes = 0, name = 0, next_name = no_row, parent_row = no_row; }; struct Name { std::string text, lower; uint32_t first = no_row; }; struct RawEntry { uint64_t id = 0, parent = 0, size = 0, modified = 0, created = 0, accessed = 0; uint32_t attributes = 0; std::string name; }; class Volume { public: mutable std::shared_mutex mutex; std::string root; uint64_t serial = 0, root_id = 0, journal_id = 0, next_usn = 0, generation = 1, name_generation = 1; uint64_t checkpoint_usn = 0; uint64_t pending_updates = 0; uint64_t files = 0, directories = 0; bool ready = false; std::string state = "indexing"; std::vector entries; std::deque names; std::vector sorted_names; std::unordered_map directory_rows; explicit Volume(std::string source) : root(std::move(source)) {} void add_initial(RawEntry record); void finish(); void compact(); void replace_links(uint64_t id, const std::vector& records); std::string full_path(uint32_t row) const; Result result(uint32_t row, bool with_path = true) const; std::vector find(const Query& query, uint64_t stop_after, const std::function& cancelled, bool ordered = false) const; void save(const std::filesystem::path& path) const; static std::shared_ptr load(const std::filesystem::path& path, std::string root, uint64_t serial); private: std::unordered_map name_ids_; std::vector name_masks_; std::unordered_map> added_ids_; // Intrusive child chains use four bytes per row, with one head per parent. // Keying heads by NTFS file reference preserves descendants on directory moves. std::unordered_map first_children_; std::vector next_sibling_; size_t base_count_ = 0, sorted_name_count_ = 0; uint32_t intern(std::string name); void add(RawEntry record, bool delta); std::vector rows_for_id(uint64_t id) const; uint32_t parent_row(uint32_t row) const; void link_child(uint32_t row); void unlink_child(uint32_t row); std::vector find_literals(const Query& query, const std::vector& literals, uint64_t stop_after, const std::function& cancelled, bool ordered) const; }; struct RowRef { uint32_t volume, row; }; class Engine { public: mutable std::shared_mutex mutex; std::vector> volumes; Reply search(const Request& request, const std::function& cancelled = [] { return false; }); Reply status() const; void set_volumes(std::vector> value); private: struct Cached { Request request; uint64_t generation = 0; std::vector> volumes; std::vector rows; }; std::mutex cache_mutex_; std::shared_ptr cache_; uint64_t topology_ = 1; }; }