ravel
Deterministic simulation testing for C++. Seed a bug, replay it exact.
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Attributes | List of all members
ravel::Disk Class Reference

A virtual disk holding named files, with the failure behavior that makes storage code hard to get right. More...

#include <disk.hpp>

Classes

class  Operation
 An operation in flight; co_await it to get its result. More...
 

Public Member Functions

 Disk (DiskId id, std::string name, DiskFaultSpec fault, Scheduler &scheduler, VirtualRng &rng, Trace &trace)
 Created by Simulation::add_disk; you do not construct one yourself.
 
 Disk (const Disk &)=delete
 Pending operations refer to this object, so it must never move.
 
Disk & operator= (const Disk &)=delete
 
const std::string & name () const noexcept
 The name given to add_disk.
 
const DiskFaultSpec & fault () const noexcept
 The fault settings this disk was created with.
 
Operation< DiskStatus > write (std::string path, std::uint64_t offset, std::string data)
 Writes data at offset, creating the file if it does not exist and growing it (with zero bytes) if needed.
 
Operation< ReadResult > read (std::string path, std::uint64_t offset, std::uint64_t length)
 Reads up to length bytes at offset, seeing every completed write.
 
Operation< DiskStatus > sync (std::string path)
 Makes every write to the file that completed before this call was issued durable, and the file's creation (see above).
 
Operation< DiskStatus > rename (std::string from, std::string to)
 Renames a file, replacing to if it exists. NotFound if from does not.
 
Operation< DiskStatus > remove (std::string path)
 Removes a file. NotFound if it does not exist.
 
Operation< DiskStatus > sync_dir (std::string dir)
 Makes durable every directory change, made before this call was issued, up to the last one that touched dir (a file created, renamed into or out of it, or removed from it).
 
Operation< ListResult > list (std::string dir)
 The entries directly inside dir.
 
void crash ()
 Power loss.
 
std::uint64_t crash_count () const noexcept
 How many times crash() has been called.
 
std::uint64_t file_size (const std::string &path) const
 The file's size as reads see it (0 if it does not exist).
 
std::string durable_contents (const std::string &path) const
 The file as a crash right now would leave it at best: only durable data, and empty unless the file's name is durable too.
 
bool durable_exists (const std::string &path) const
 Whether the file's name would survive a crash right now.
 
std::uint64_t used_bytes () const
 Total bytes of all files, as reads see them.
 

Static Public Attributes

static constexpr std::size_t kSectorSize = 512
 A write torn by a crash is cut at a multiple of this many bytes.
 

Detailed Description

A virtual disk holding named files, with the failure behavior that makes storage code hard to get right.

Data. Like a real disk with a page cache, a write is visible to reads at once but is only durable after sync(path). crash() models power loss: every write that was not yet synced independently either vanishes, survives whole, or survives only in part (a torn write, cut at a 512-byte sector boundary).

Names. Creating a file, renaming it and removing it are visible at once too, but each changes the directory only in memory until it is made durable. Directory changes reach the disk in the order they were made, so a crash keeps some prefix of the pending ones (possibly none). Two calls make them durable:

The outcome of each crash decision is a random choice, and the simplest outcome (what shrinking steers toward) is always that the change is lost.

co_await disk.write("wal/log", 0, "record"); co_await disk.sync("wal/log"); // "record" now survives crash()

Paths use '/' as the separator and have no leading slash. Directories exist implicitly: a directory is there as long as a file is under it, and "" is the root. All operations are awaited and take virtual time. No real files are touched.

Member Function Documentation

◆ crash()

void ravel::Disk::crash ( )

Power loss.

Applies the crash rules above to unsynced writes and directory changes, and fails every operation still in flight with DiskStatus::Crashed. Instant: call it from a task, or from an invariant to inspect the aftermath.

◆ crash_count()

std::uint64_t ravel::Disk::crash_count ( ) const
inlinenoexcept

How many times crash() has been called.

A process that a crash kills can read this before starting and stop once it changes: an operation that completed just before the crash is not enough to keep going.

◆ list()

Operation< ListResult > ravel::Disk::list ( std::string  dir)

The entries directly inside dir.

NotFound if dir has none (except the root, which may be empty).

◆ read()

Operation< ReadResult > ravel::Disk::read ( std::string  path,
std::uint64_t  offset,
std::uint64_t  length 
)

Reads up to length bytes at offset, seeing every completed write.

NotFound if the file does not exist.


The documentation for this class was generated from the following file: