1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Per-shard persistence file naming — the single source of truth for the
//! on-disk layout. Every kevy data dir is a flat set of per-shard files:
//!
//! - `dump-{i}.rdb` — shard `i`'s snapshot ([`crate::save_snapshot`])
//! - `aof-{i}.aof` — shard `i`'s append-only log ([`crate::Aof`])
//! - `shards.meta` — the layout record ([`crate::ShardsMeta`])
//! - `LOCK` — the directory's advisory lock ([`crate::DirLock`])
//!
//! The server runtime, the embedded store, and the reshard engine all
//! derive their paths from here, so a dir written by one is readable by
//! the others (the embedded store's custom-filename opt-out aside).
//!
//! ```
//! use kevy_persist::layout;
//!
//! let dir = kevy_tmpdir::unique_dir("layout-doc");
//! kevy_persist::save_snapshot(&kevy_store::Store::new(), &layout::snapshot_path(&dir, 0))?;
//! std::fs::write(layout::aof_path(&dir, 1), kevy_persist::AOF2_MAGIC)?;
//! // a dir one writer laid out is read back by anything deriving the same names
//! assert_eq!(layout::infer_files_n(&dir), 2);
//! # std::fs::remove_dir_all(&dir)?;
//! # Ok::<(), std::io::Error>(())
//! ```
use ;
/// Shard `i`'s snapshot file name.
///
/// ```
/// assert_eq!(kevy_persist::layout::snapshot_file(3), "dump-3.rdb");
/// ```
/// Shard `i`'s AOF file name.
///
/// ```
/// assert_eq!(kevy_persist::layout::aof_file(3), "aof-3.aof");
/// ```
/// Shard `i`'s snapshot path under `dir`.
///
/// ```
/// use std::path::Path;
/// let p = kevy_persist::layout::snapshot_path(Path::new("/data"), 0);
/// assert_eq!(p, Path::new("/data/dump-0.rdb"));
/// ```
/// Shard `i`'s AOF path under `dir`.
///
/// ```
/// use std::path::Path;
/// let p = kevy_persist::layout::aof_path(Path::new("/data"), 0);
/// assert_eq!(p, Path::new("/data/aof-0.aof"));
/// ```
/// Shard `i`'s staging ring path under `dir`: the AOF's name plus
/// `.stage`.
///
/// ```
/// use std::path::Path;
/// use kevy_persist::layout::{aof_path, stage_path};
///
/// let ring = stage_path(Path::new("/data"), 2);
/// assert_eq!(ring, Path::new("/data/aof-2.aof.stage"));
/// assert_eq!(ring.with_extension(""), aof_path(Path::new("/data"), 2));
/// ```
/// The advisory-lock file's path under `dir` ([`crate::DirLock`]).
///
/// ```
/// use std::path::Path;
/// assert_eq!(kevy_persist::layout::lock_path(Path::new("/data")), Path::new("/data/LOCK"));
/// ```
/// The layout record's path under `dir`.
///
/// ```
/// use kevy_persist::{Routing, ShardsMeta, layout};
///
/// let dir = kevy_tmpdir::unique_dir("layout-meta-doc");
/// ShardsMeta::new(2, Routing::KevyHash).write(&layout::shards_meta_path(&dir))?;
/// assert!(dir.join("shards.meta").exists());
/// # std::fs::remove_dir_all(&dir)?;
/// # Ok::<(), std::io::Error>(())
/// ```
/// Shard `i`'s cold-segment directory under `dir` — the segment files
/// plus the manifest that makes them real. Per shard, like the AOF it
/// stitches into: replay threads never share a manifest.
///
/// ```
/// use std::path::Path;
/// let d = kevy_persist::layout::segs_dir(Path::new("/data"), 1);
/// assert_eq!(d, Path::new("/data/segs-1"));
/// ```
/// Highest `dump-{i}.rdb` / `aof-{i}.aof` index + 1 found in `dir`, or 0
/// for no per-shard files. The shard count of a meta-less legacy dir.
///
/// ```
/// use kevy_persist::layout;
///
/// let dir = kevy_tmpdir::unique_dir("layout-infer-doc");
/// assert_eq!(layout::infer_files_n(&dir), 0);
/// std::fs::write(dir.join(layout::aof_file(2)), b"")?; // shards 0 and 1 wrote nothing
/// assert_eq!(layout::infer_files_n(&dir), 3);
/// # std::fs::remove_dir_all(&dir)?;
/// # Ok::<(), std::io::Error>(())
/// ```