New adaptation policy

This commit is contained in:
Efim Beshmenev
2026-08-13 23:42:26 +03:00
parent bbb43dbe57
commit 3770224eaf
16 changed files with 2533 additions and 489 deletions
@@ -151,6 +151,89 @@ struct AdaptationTelemetry {
std::size_t last_evidence_windows = 0;
};
// The production policy is deliberately small. It does not try to infer a
// workload phase from every operation; AdaptiveSequence consults these limits
// only when its logical capacity grows or shrinks. The crossover value is a
// calibratable constant and is updated from the focused benchmark rather than
// from the retired benchmark matrix.
struct ResizePolicyConfig {
std::size_t minimum_tiered_size = 4 * 1024;
std::size_t shrink_denominator = 8; // shrink at 12.5% occupancy
};
class ResizePolicy {
public:
explicit ResizePolicy(ResizePolicyConfig config = {}, TieredConfig tiered = {}) noexcept
: config_(normalize(config)), active_tiered_(normalize_tiered(tiered)) {}
void set_tiered_config(TieredConfig tiered) noexcept {
active_tiered_ = normalize_tiered(tiered);
}
// Kept as no-op compatibility hooks so a custom CostModelPolicy can still
// be substituted for experiments without putting policy work on the
// default read/edit paths.
void observe(const OperationSample&) noexcept {}
[[nodiscard]] bool decision_ready() const noexcept { return false; }
[[nodiscard]] std::optional<AdaptationDecision>
recommended_decision(StorageMode, std::size_t, TieredConfig) noexcept {
return std::nullopt;
}
void on_transition(StorageMode from,
StorageMode to,
TieredConfig active_config) noexcept {
const auto normalized = normalize_tiered(active_config);
if (from == StorageMode::vector && to == StorageMode::tiered) {
++telemetry_.vector_to_tiered;
} else if (from == StorageMode::tiered && to == StorageMode::vector) {
++telemetry_.tiered_to_vector;
} else if (from == StorageMode::tiered && to == StorageMode::tiered) {
++telemetry_.tiered_rebuilds;
if (normalized.leaf_capacity == active_tiered_.leaf_capacity) {
++telemetry_.tiered_directory_rebuilds;
} else {
++telemetry_.tiered_leaf_rebuilds;
}
}
active_tiered_ = normalized;
}
void on_transition(StorageMode from, StorageMode to) noexcept {
on_transition(from, to, active_tiered_);
}
void reset() noexcept { telemetry_ = {}; }
[[nodiscard]] const ResizePolicyConfig& config() const noexcept { return config_; }
[[nodiscard]] const AdaptationTelemetry& telemetry() const noexcept {
return telemetry_;
}
private:
static ResizePolicyConfig normalize(ResizePolicyConfig config) noexcept {
config.minimum_tiered_size = std::max<std::size_t>(1,
config.minimum_tiered_size);
config.shrink_denominator = std::max<std::size_t>(2,
config.shrink_denominator);
return config;
}
static TieredConfig normalize_tiered(TieredConfig config) noexcept {
config.leaf_capacity = std::clamp<std::size_t>(
config.leaf_capacity, 4, 1U << 20U);
config.directory_fanout = std::clamp<std::size_t>(
config.directory_fanout, 2, 1U << 16U);
config.directory_levels = std::clamp<std::size_t>(
config.directory_levels, 1, 8);
return config;
}
ResizePolicyConfig config_{};
TieredConfig active_tiered_{};
AdaptationTelemetry telemetry_{};
};
class CostModelPolicy {
public:
static constexpr std::size_t candidate_count = 5;