hash_name_matcher.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include <string_view>
  7. #include "../../../state/build_data/hash_names/definition.h"
  8. #include "../../../state/build_data/scenarios/definition.h"
  9. namespace sunrise::client::content::hash_names {
  10. namespace names_state = state::build_data::hash_names;
  11. /**
  12. * Named objects the class sweep finds. The measured live count is 241,586.
  13. * Neither a bubble nor a spawn set stores its own name, so names are recovered by hashing every
  14. * id the installed objects carry and matching it against the hashes they declare.
  15. */
  16. inline constexpr std::size_t kTagCapacity = 262'144;
  17. /**
  18. * Tags one slice reads, shared out between the readers.
  19. * The slice waits for every reader, so this bounds how long it blocks the frame. At the measured
  20. * cost of a read that is a few tens of milliseconds.
  21. */
  22. inline constexpr std::size_t kBatchTags = 2048;
  23. /** Longest id worth hashing. Anything longer cannot be a bubble name. */
  24. inline constexpr std::size_t kRunCapacity = names_state::kNameLength;
  25. /** Underscore-separated tokens one id may carry. */
  26. inline constexpr std::size_t kTokenCapacity = 12;
  27. /**
  28. * The target hashes and the rows one reader resolves against them.
  29. * Several readers match at once. The targets are shared and never written; the rows belong to one
  30. * reader alone and are merged when it joins, so nothing here locks.
  31. */
  32. struct MatchState {
  33. /** Ascending unique target hashes, shared and read-only. */
  34. std::span<const std::uint32_t> targets;
  35. /** Rows parallel to the targets, written only by the reader that owns them. */
  36. std::span<names_state::Name> resolved;
  37. };
  38. /** Fixed working storage for one extraction pass, kept off the caller stack. */
  39. struct Storage {
  40. /** Hashes the published destinations declare, ascending and unique. */
  41. std::array<std::uint32_t, names_state::kNameCapacity> targets{};
  42. std::size_t targetCount{};
  43. /** Resolved rows, parallel to targets. An unresolved row keeps a zero length. */
  44. std::array<names_state::Name, names_state::kNameCapacity> resolved{};
  45. std::size_t resolvedCount{};
  46. /** Named-object tags the sweep found, read in order so the block cache keeps hitting. */
  47. std::array<std::uint32_t, kTagCapacity> tags{};
  48. std::size_t tagCount{};
  49. /** Tag the next batch resumes from, so the pass continues across calls. */
  50. std::size_t cursor{};
  51. /** Tick the pass started on, so every report says what the pass cost. */
  52. std::uint64_t startedTick{};
  53. /** Set once the targets, the free name pass, and the sweep are done. */
  54. bool collected{};
  55. /** Set when the pass found more objects than storage holds, which no retry can fix. */
  56. bool invalid{};
  57. };
  58. /** Clears one extraction pass without freeing process-owned outer storage. */
  59. void reset(Storage& storage) noexcept;
  60. /**
  61. * Records every hash the given layouts and the published spawn sets declare.
  62. * @param storage Pass storage receiving the ascending unique nonzero target set.
  63. * @param definitions Destination layouts whose bubble hashes are named.
  64. * @return True when at least one target was found.
  65. */
  66. [[nodiscard]] bool
  67. collect_targets(Storage& storage,
  68. std::span<const state::build_data::scenarios::Definition> definitions) noexcept;
  69. /**
  70. * Offers one id, keeping the shortest name that gives a target hash.
  71. * Every underscore-bounded prefix and suffix of the id is tried, because a bubble name is usually
  72. * one token of a longer object name.
  73. * @param state One reader's targets and rows.
  74. * @param text Candidate id.
  75. */
  76. void offer(MatchState& state, std::string_view text) noexcept;
  77. /**
  78. * Offers every id inside one blob.
  79. * @param state One reader's targets and rows.
  80. * @param blob Whole object bytes.
  81. */
  82. void offer_blob(MatchState& state, std::span<const std::byte> blob) noexcept;
  83. /** @param storage Pass storage. @return Its targets and its own rows. */
  84. [[nodiscard]] MatchState match_state(Storage& storage) noexcept;
  85. /**
  86. * Folds one reader's rows into the pass, keeping the shortest name for every target.
  87. * @param storage Pass storage.
  88. * @param rows Rows one reader resolved, parallel to the targets.
  89. */
  90. void merge(Storage& storage, std::span<const names_state::Name> rows) noexcept;
  91. /**
  92. * Adds one swept tag to an unfinished pass.
  93. * @param storage Pass storage.
  94. * @param tag Named-object tag.
  95. * @return False when the pass is finished or storage is full.
  96. */
  97. [[nodiscard]] bool add_tag(Storage& storage, std::uint32_t tag) noexcept;
  98. /**
  99. * Packs the resolved rows into ascending hash order for publishing.
  100. * @param storage Pass storage whose resolved count is set here.
  101. */
  102. void finish(Storage& storage) noexcept;
  103. } // namespace sunrise::client::content::hash_names