// Environment configuration: geometry and runtime options
// Textbook section: Volume II, chapter 9, "Environment configuration",
//   sections "Geometry", "Runtime options".
// What it demonstrates: setting the geometry (lower/now/upper/growth/shrink) when
//   creating the environment; setting and reading runtime options: writethrough_threshold,
//   merge_threshold, sync_period/sync_bytes, prefault_write_enable.
// Build: g++ -std=c++17 -I<libmdbx-include> -I../common 11-geometry-options.c++ -lmdbx
// Run: ./11-geometry-options
// Expected output (values may differ on other platforms):
//   geometry: lower=8 MiB now=16 MiB upper=64 MiB grow=8 MiB shrink=2 MiB
//   merge_threshold_dot16=21845 (default ~33%)
//   prefault_write_enable=1
//   ok: geometry and runtime options set/read
// On Windows writethrough_threshold is not supported (§10.5): the value
// is not set and the effective one is printed (2147483647).
// On failure — message to stderr and exit 1.
//
// SPDX-License-Identifier: Apache-2.0

#include <iostream>
#include <string>

#include "common.h++"
#include <mdbx.h++>

int main() {
  try {
    const std::string path = std::string(example::tmpdir()) + "/mdbx-11-geometry-options.mdbx";
    mdbx::env::remove(path);

    // Geometry: lower/current/upper size limits of the database, growth step,
    // shrink threshold. Here — a compact database for the example.
    mdbx::env::geometry geo;
    geo.size_lower = 8 * mdbx::env::geometry::MB;
    geo.size_now = 16 * mdbx::env::geometry::MB;
    geo.size_upper = 64 * mdbx::env::geometry::MB;
    geo.growth_step = 8 * mdbx::env::geometry::MB;
    geo.shrink_threshold = 2 * mdbx::env::geometry::MB;

    mdbx::env_managed env(path, mdbx::env_managed::create_parameters().set_geometry(geo),
                          mdbx::env::operate_parameters());

    // Runtime options: we set them and read them back.
    // MDBX_opt_writethrough_threshold is not supported on Windows (Volume II, §10.5):
    // there it is always write-through, and set_option accepts only default/0/UINT_MAX,
    // any other value -> MDBX_EINVAL.
#if !defined(_WIN32)
    env.set_extra_option(mdbx::env::extra_runtime_option::writethrough_threshold, 1 << 20);
#endif
    env.set_extra_option(mdbx::env::extra_runtime_option::merge_threshold_dot16, 65536 / 3);
    // sync_bytes = 256 KiB
    env.set_sync_threshold(256 * 1024);
    env.set_extra_option(mdbx::env::extra_runtime_option::prefault_write_enable, 1);

    using opt = mdbx::env::extra_runtime_option;
    const uint64_t wt = env.extra_option(opt::writethrough_threshold);
    const uint64_t mt = env.extra_option(opt::merge_threshold_dot16);
    const uint64_t sb = env.extra_option(opt::sync_bytes);
    const uint64_t pfw = env.extra_option(opt::prefault_write_enable);
    std::cout << "writethrough_threshold=" << wt << "\n";
    std::cout << "merge_threshold_dot16=" << mt << " (" << (mt * 100 / 65536) << "% of page)\n";
    std::cout << "sync_bytes=" << sb << "\n";
    std::cout << "prefault_write_enable=" << pfw << "\n";

    // The geometry read back after opening.
    auto info = env.get_info();
    const auto &g = info.mi_geo;
    std::cout << "geometry: lower=" << g.lower / 1000 << " KiB now=" << g.current / 1000
              << " KiB upper=" << g.upper / 1000 << " KiB\n";

    std::cout << "ok: geometry and runtime options set/read\n";
    return EXIT_SUCCESS;
  } catch (const std::exception &ex) {
    std::cerr << "error: " << ex.what() << "\n";
    return EXIT_FAILURE;
  }
}