};
/// Rewrite-planner limits derived from the [rewrite] config section.
+///
+/// Every field is loaded by BeesConfig::load_rewrite_policy(); the authoritative
+/// defaults live in bees-config-v2.cc. The C++ member initializers below are
+/// deliberately invalid sentinels (0 / false, or UINT64_MAX where 0 is a valid
+/// value) so a policy that bypasses the loader fails loudly — rejecting
+/// everything or mis-costing obviously — instead of running on plausible
+/// defaults. Directly-constructed policies in tests and benchmarks must set the
+/// fields they exercise (see test/test-bees-plan.cc default_policy()).
struct BeesRewritePolicy {
- uint64_t m_dedupe_max = 100;
+ uint64_t m_dedupe_max = 0;
/// Maximum number of dedupe operations allowed against a single
/// compressed destination extent. A compressed extent can be
/// physically minimal yet hold many logical blocks, so a plan can
/// pile many dedupe ops onto it, exploding ref count (~100 bytes
/// per ref) for almost no physical space gain. Allow at most 2
/// (covers two compressed files with identical content but
- /// mismatched extent boundaries); reject more. Default 2.
- uint64_t m_compressed_dedupe_max = 2;
- uint64_t m_copy_max = 100;
- uint64_t m_hole_max = 100;
- uint64_t m_total_max = 100;
+ /// mismatched extent boundaries); reject more. Config default 2.
+ uint64_t m_compressed_dedupe_max = 0;
+ uint64_t m_copy_max = 0;
+ uint64_t m_hole_max = 0;
+ uint64_t m_total_max = 0;
/// Maximum references a single extent may accumulate before bees stops
/// adding more (rewrite.refs-max; default 9999, clamped to the ioctl hard
/// ceiling BEES_MAX_EXTENT_REF_COUNT, which "unlimited" resolves to).
/// Soft cap that prevents runaway plans driven by many tiny
/// extents. Paired with m_candidate_max_bytes (a soft cap on
/// total candidate bytes); whichever ceiling is hit first stops
- /// candidate accumulation. Default 1024.
- uint64_t m_candidate_max_count = 1024;
+ /// candidate accumulation. Config default 1024.
+ uint64_t m_candidate_max_count = 0;
/// Maximum total logical bytes across all candidate extents.
/// Soft cap that prevents runaway plans driven by a few huge
- /// extents. Paired with m_candidate_max_count. Default: 512 MB
+ /// extents. Paired with m_candidate_max_count. Config default 512 MB
/// (4× max extent length).
- uint64_t m_candidate_max_bytes = 512ULL * 1024 * 1024;
+ uint64_t m_candidate_max_bytes = 0;
/// Minimum net bytes a rewrite must free — good_blocks minus
/// bad_blocks, in bytes. A rewrite is accepted only if
/// (good - bad) * block_size >= max(m_free_min_bytes,
/// m_free_min_ratio * total_bytes). Exactly one of the two
- /// forms is set by the config parser: a percentage sets the
- /// ratio, a byte-count sets the absolute floor.
+ /// forms is set by the config parser (which zeroes both first): a
+ /// percentage sets the ratio, a byte-count sets the absolute floor.
uint64_t m_free_min_bytes = 0;
- double m_free_min_ratio = 0.5;
+ double m_free_min_ratio = 0.0;
/// Maximum hash-conflict restarts per extent.
- uint64_t m_restart_max = 4;
+ uint64_t m_restart_max = 0;
/// Maximum hashes inserted per extent during scan (MinHash
- /// fingerprint size). Default 100 (~0.3% sample at 128 MB).
- uint64_t m_insert_sample_max = 100;
+ /// fingerprint size). Config default 100 (~0.3% sample at 128 MB).
+ uint64_t m_insert_sample_max = 0;
/// Check for hash insert collisions during scan.
- bool m_insert_conflict_check = true;
- /// Match algorithm selection. When true (default), use
- /// anchor-extend matching; otherwise greedy-forward.
- bool m_match_anchor_extend = true;
+ bool m_insert_conflict_check = false;
+ /// Match algorithm selection. When true, use anchor-extend
+ /// matching; otherwise greedy-forward. Config default true.
+ bool m_match_anchor_extend = false;
/// Lock inodes of all extent refs before planning.
- bool m_inode_locking = true;
+ bool m_inode_locking = false;
/// Build Plan A (start extent as dedupe dst). When true
- /// (default), scan_next_plan creates a BeesStartAsDstPlan that
+ /// (config default), scan_next_plan creates a BeesStartAsDstPlan that
/// looks for src candidates whose hashes match the start extent
/// and dedupes matching ranges into the start. When false,
/// Plan A still runs for hole-punch and unreachable-block
/// older copy in this scan pass. Conceptually: "keep older
/// copies" — when an older indexed extent has matching content,
/// the newer start extent is replaced by a reference to it.
- bool m_keep_older = true;
+ bool m_keep_older = false;
/// Build Plan B (start extent as dedupe src). When true
- /// (default), scan_next_plan creates a BeesStartAsSrcPlan that
+ /// (config default), scan_next_plan creates a BeesStartAsSrcPlan that
/// looks for dst candidates whose hashes match the start
/// extent and dedupes the start's content into matching
/// extents. When false, Plan B is suppressed entirely; the
/// Conceptually: "keep newer copies" — when an older indexed
/// extent matches the newly-scanned start, the older copy is
/// replaced by a reference to start.
- bool m_keep_newer = true;
+ bool m_keep_newer = false;
/// Per-ref space-debt weight, in bytes, used by the do-nothing
/// cost model (see docs/config-file.md and do-nothing-plan.md §4).
/// Each ref a plan adds to the filesystem costs this many bytes of
/// can stall a worker and every task queued behind that extent. When
/// V exceeds this budget the planner abandons the exact search for a
/// linear-time greedy cover and stops gathering further candidates.
- /// See docs/config-file.md; a real default is kept here (not a loud
- /// sentinel) so directly-constructed policies in tests/benchmarks get
- /// the exact DP for small inputs. `unlimited` disables the fallback.
- uint64_t m_plan_max_vertices = 16384;
+ /// See docs/config-file.md. Config default 16384; `unlimited` disables
+ /// the fallback. Tests/benchmarks that exercise the search must set this
+ /// (0 forces the greedy path immediately).
+ uint64_t m_plan_max_vertices = 0;
/// Buffer size for source-side reads in the materialize copy
/// loop and the block_map_fetch hashing pass. Larger values
/// amortise pread syscall and ref-selection cost over more bytes;
/// smaller values reduce per-thread RSS. Should be a multiple of
/// the filesystem sectorsize; non-multiples just waste a sliver
- /// of the last block in each chunk. Default: 1 MiB.
- uint64_t m_read_size = 1024 * 1024;
+ /// of the last block in each chunk. Config default 1 MiB.
+ uint64_t m_read_size = 0;
};
/**
//
// Build (from test/):
// make test-bees-plan-lib.o
-// clang++ $(BEES_CXXFLAGS) -I../src -o bench-bees-plan \
+// clang++ $(BEES_CXXFLAGS) -I../src -ffunction-sections -fdata-sections \
+// -Wl,--gc-sections -o bench-bees-plan \
// bench-bees-plan.cc test-bees-plan-lib.o -L../lib -lcrucible -lpthread -latomic
+// (--gc-sections is required: test-bees-plan-lib.o is all of bees-plan.cc,
+// which contains functions this bench never calls — CostReport's operator<<
+// and BeesPlan::print (needing pretty(double) and BeesExtent::bytenr) and
+// BeesCandidateQueue::pick_best_candidate (needing BeesExtent::phys_size) —
+// that reference symbols this standalone link does not provide. The section
+// GC drops them because nothing reachable from main() calls them.)
//
-// Usage: ./bench-bees-plan [num_matches] [region_blocks] [max_match_blocks] [seed]
+// Usage: ./bench-bees-plan [num_matches] [region_blocks] [max_match_blocks] \
+// [seed] [per-type-max] [total-max]
#include "bees-plan.h"
policy.m_copy_max = PerType;
policy.m_hole_max = PerType;
policy.m_total_max = TotalMax;
+ // BeesRewritePolicy's C++ default is now an invalid sentinel (0), which
+ // would force the greedy path immediately, so set the DP budget explicitly.
+ // Config default 16384; raise it to profile the exact DP at higher V.
+ policy.m_plan_max_vertices = 16384;
const auto t0 = chrono::steady_clock::now();
const auto res = scan_next_plan_shortest_path(in, policy);