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
//! syncless: ordered, atomic storage without durability guarantees.
//!
//! Many times you don't want to pay the cost of continuous fsyncs, and are ok
//! with losing the latest updates if an OS crash/power outage were to happen
//! and the user is unlucky - but it's **not acceptable** to corrupt older
//! data. Think of cases like "browser bookmarks" or "history": synchronous
//! requirements are overkill for these (and stressful on the entire system).
//!
//! Once `syncless` has opened a file (except for hardware errors or bugs)
//! writes are **atomic** and **consistently ordered**: if you see a write you
//! will see all of it, and all prior writes.
//!
//! Writes are **not isolated** (a single reader/writer is assumed) and **not
//! durable**: data may remain buffered in memory and be lost on crash or
//! power failure. However, crash recovery will never expose torn writes or
//! corrupt earlier data.
//!
//! ## Guarantees
//!
//! - Atomic visibility of individual writes
//! - Ordered visibility of writes
//! - Crash-safe recovery of previously visible data
//!
//! ## Non-guarantees
//!
//! - Durability (recent writes may be lost)
//! - Isolation (single writer assumed)
//! - Multi-process coordination
//!
//! ## Example: atomically storing a JSON file
//!
//! This saves a JSON blob (perhaps your program's config?) using syncless
//! so it either gets the old or new one, never a corrupted version.
//! In practice you would probably keep the Store<Writable> object around,
//! as reloading it can be expensive if it has many changes.
//!
//! ```no_run
//! use syncless::{open, Store, Writable, Error};
//!
//! pub fn save_config(
//! store: &mut Store<syncless::Writable>,
//! json: &str,
//! ) -> Result<(), Error> {
//! store.write(0, json.as_bytes())
//! }
//!
//! pub fn load_config(
//! store: &mut Store<syncless::ReadOnly>
//! ) -> Result<String, Error> {
//! let mut buf = vec![0u8; store.size() as usize];
//!
//! store.read(0, &mut buf)?;
//! let s = std::str::from_utf8(&buf)
//! .map_err(|e| Error::CorruptRecord)?;
//! Ok(s.to_owned())
//! }
//! ```
/// Errors from our functions.
/// Store comes in two flavors: ReadOnly and Writable.
/// Phantom data to make a Readonly store
;
/// Phantom data to make a Writable store
;
/// How to open the Syncless store file:
pub use open_readonly;
pub use open;
use StoreBase;