94 lines
include/checkpoint_manager.h
Declares CheckpointManager, Snapshot, and the restore/save contract.
// CheckpointManager: merges versioned configuration snapshots on service restart.
#pragma once
#include <cstdint>
#include <cstdio>
#include <string>
#include <unordered_map>
#include <vector>
 
// Abstract configuration store interface used during restore.
class IConfigStore {
public:
  virtual ~IConfigStore() = default;
  // Sets a key to value if the incoming version is newer than the stored version.
  // Parameters:
  //   key     - configuration key to update
  //   value   - new value
  //   version - version of the snapshot providing this value
  virtual void set(const std::string& key, const std::string& value,
                   uint32_t version) = 0;
  // Returns the version of the last set() call that updated this key, or 0 if unset.
  virtual uint32_t versionOf(const std::string& key) const = 0;
};
 
// One replica's configuration snapshot.
struct Snapshot {
  uint32_t version;    // monotonically increasing per-replica; higher = more recent
  uint32_t instanceId; // originating replica identifier
  std::unordered_map<std::string, std::string> values; // key-value pairs in this snapshot
};
 
// On-disk file header (immediately followed by entryCount Snapshot records).
struct CheckpointHeader {
  uint32_t magic;      // must equal CHECKPOINT_MAGIC = 0xC0FFEE01
  uint32_t entryCount; // number of Snapshot records that follow in the file
  uint32_t formatVer;  // file format version; must equal 1
};
 
static constexpr uint32_t CHECKPOINT_MAGIC = 0xC0FFEE01u;
 
// Reads and writes versioned configuration snapshots to a checkpoint file.
class CheckpointManager {
public:
  // Parameters:
  //   path - path to the checkpoint file; created on first save
  // Returns: new CheckpointManager instance
  explicit CheckpointManager(const char* path);
  ~CheckpointManager();
 
  // Saves one snapshot to the checkpoint file.
  // Parameters:
  //   snap - snapshot to append
  // Returns: true if the snapshot was written successfully
  bool save(const Snapshot& snap);
 
  // Reads all snapshots from the checkpoint file and applies them to the store.
  // Snapshots must be applied in ascending version order so higher-version values win.
  // entryCount from the file header must be validated before any allocation.
  // Parameters:
  //   store - destination configuration store
  // Returns: true if at least one snapshot was applied; false on file error or empty file
  bool restore(IConfigStore& store);
 
  // Returns true if the file is open and usable.
  bool isOpen() const { return fp_ != nullptr; }
 
private:
  std::FILE* fp_ = nullptr;
 
  // Reads one Snapshot from the current file position.
  // Parameters:
  //   snap - output structure filled with the record data
  // Returns: true if the snapshot was fully read
  bool readSnapshot(Snapshot& snap);
 
  // Writes one Snapshot at the current file position.
  // Parameters:
  //   snap - snapshot to serialise and write
  // Returns: true if all bytes were written successfully
  bool writeSnapshot(const Snapshot& snap);
 
  // Applies a snapshot's key-value pairs to the store.
  // Parameters:
  //   store - destination store
  //   snap  - snapshot to apply
  // Returns: void
  void applySnapshot(IConfigStore& store, const Snapshot& snap);
 
  // Checks whether a snapshot at snapVer should overwrite a value at storeVer.
  // Parameters:
  //   snapVer  - version of the incoming snapshot
  //   storeVer - current stored version for comparison
  // Returns: true if snapVer strictly exceeds storeVer
  bool shouldApply(uint32_t snapVer, uint32_t storeVer) const;
};