Skip to main content

coven_sync/
file_upload_settings.rs

1//! The writer's copies of the upload settings, which only its upload runs and
2//! the app's changes of a setting use (§12.3, §17.4, §17.9), and the
3//! connections its upload runs' attempts use.
4
5use super::file_upload_pool::Lane;
6use super::{FilesInner, TrailingHold};
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8
9/// The writer's copies of the upload settings, and the connections its
10/// upload runs' attempts use.
11pub struct UploadSettings {
12    /// The persisted pause setting as of the last upload run or app change;
13    /// parts check it between sends.
14    paused: AtomicBool,
15    /// Whether a self-replacement pauses this device's writes, as of the last
16    /// read of the upload queue or a completion it refused (§12.3).
17    writes_paused: AtomicBool,
18    /// How many app retries have been asked.
19    retries_asked: AtomicU64,
20    /// The connections the upload runs' attempts use, lane by lane.
21    connections: std::sync::Arc<super::file_upload_connections::UploadConnections>,
22    /// Held by an app's change of either setting, and by an upload run from
23    /// its read of the persisted settings until it has acted on them, so
24    /// neither the copies here nor a retry's answer comes from a setting
25    /// already replaced.
26    hold_change: tokio::sync::Mutex<()>,
27    /// Holds the next upload run once it has read the persisted settings,
28    /// telling the test, until the test resumes it.
29    #[cfg(test)]
30    settings_read_gate: std::sync::Mutex<
31        Option<(tokio::sync::oneshot::Sender<()>, tokio::sync::oneshot::Receiver<()>)>,
32    >,
33    /// How many times an app's change of a setting, or a run, has found
34    /// `hold_change` held and waited.
35    #[cfg(test)]
36    change_waits: tokio::sync::watch::Sender<usize>,
37}
38
39impl UploadSettings {
40    pub(super) fn new() -> Self {
41        Self {
42            paused: AtomicBool::new(false),
43            writes_paused: AtomicBool::new(false),
44            retries_asked: AtomicU64::new(0),
45            connections: std::sync::Arc::new(
46                super::file_upload_connections::UploadConnections::new(),
47            ),
48            hold_change: tokio::sync::Mutex::new(()),
49            #[cfg(test)]
50            settings_read_gate: std::sync::Mutex::new(None),
51            #[cfg(test)]
52            change_waits: tokio::sync::watch::channel(0).0,
53        }
54    }
55
56    /// The app's pause as of now.
57    pub(super) fn paused(&self) -> bool {
58        self.paused.load(Ordering::Acquire)
59    }
60    pub(super) fn set_paused(&self, paused: bool) {
61        self.paused.store(paused, Ordering::Release);
62    }
63    pub(super) fn writes_paused(&self) -> bool {
64        self.writes_paused.load(Ordering::Acquire)
65    }
66    pub(super) fn set_writes_paused(&self, paused: bool) {
67        self.writes_paused.store(paused, Ordering::Release);
68    }
69    pub(super) fn retries_asked(&self) -> u64 {
70        self.retries_asked.load(Ordering::Acquire)
71    }
72    #[cfg(test)]
73    pub(super) fn hold_after_settings_read(
74        &self,
75        gate: (tokio::sync::oneshot::Sender<()>, tokio::sync::oneshot::Receiver<()>),
76    ) {
77        *self.settings_read_gate.lock().expect("the gate is not poisoned") = Some(gate);
78    }
79    #[cfg(test)]
80    pub(super) fn take_settings_read_gate(
81        &self,
82    ) -> Option<(tokio::sync::oneshot::Sender<()>, tokio::sync::oneshot::Receiver<()>)> {
83        self.settings_read_gate.lock().expect("the gate is not poisoned").take()
84    }
85    /// Count an app retry asked, returning how many were asked before it.
86    pub(super) fn retry_asked(&self) -> u64 {
87        self.retries_asked.fetch_add(1, Ordering::AcqRel)
88    }
89
90    /// `hold_change`, for a run; a test hears each wait for it.
91    pub(super) async fn lock_hold_change(&self) -> tokio::sync::MutexGuard<'_, ()> {
92        #[cfg(test)]
93        match self.hold_change.try_lock() {
94            Ok(change) => return change,
95            Err(_) => self.change_waits.send_modify(|waits| *waits += 1),
96        }
97        self.hold_change.lock().await
98    }
99
100    /// `hold_change`, for a setting's change on its write's blocking
101    /// thread; a test hears each wait for it.
102    pub(super) fn hold_change_blocking(&self) -> tokio::sync::MutexGuard<'_, ()> {
103        #[cfg(test)]
104        match self.hold_change.try_lock() {
105            Ok(change) => return change,
106            Err(_) => self.change_waits.send_modify(|waits| *waits += 1),
107        }
108        self.hold_change.blocking_lock()
109    }
110
111    /// Wait until a setting's change or a run finds `hold_change` held and
112    /// waits, after this call.
113    #[cfg(test)]
114    pub(super) fn change_waits_from_now(&self) -> impl std::future::Future<Output = ()> {
115        let mut waits = self.change_waits.subscribe();
116        let now = *waits.borrow_and_update();
117        async move {
118            coven_foundation::clock::within(waits.wait_for(|waits| *waits > now))
119                .await
120                .expect("a change waits for the run")
121                .expect("the waits are kept");
122        }
123    }
124}
125
126impl FilesInner {
127    /// The connections `lane`'s attempts took beside their own, for parts
128    /// sent together (§17.9).
129    pub(super) fn connections_beside(&self, lane: Lane) -> usize {
130        self.uploads.connections.beside(lane)
131    }
132    /// The upload worker's count of `lane`'s attempts in flight.
133    pub(super) fn set_lane_attempts(&self, lane: Lane, attempts: usize) {
134        self.uploads.connections.set_attempts(lane, attempts);
135    }
136    /// Whether an upload of `lane` is ready and waits for a connection.
137    pub(super) fn set_lane_waiting(&self, lane: Lane, waiting: bool) {
138        self.uploads.connections.set_waiting(lane, waiting);
139    }
140    /// Another connection for a part an attempt in `lane` sends beside its
141    /// own, if the lane has one free under the upload limit and no upload of
142    /// it waits to start (§17.9).
143    pub(super) fn spare_connection(&self, lane: Lane) -> Option<super::SpareConnection> {
144        self.uploads.connections.spare(lane, self.transfers.limits().uploads.get())
145    }
146    /// Resolves once a connection taken beside an attempt has ended.
147    pub(super) async fn connection_freed(&self) {
148        self.uploads.connections.freed().await;
149    }
150    /// Whether the worker last found an upload of `lane` waiting for a
151    /// connection, for a test.
152    #[cfg(test)]
153    pub(super) fn lane_waiting(&self, lane: Lane) -> bool {
154        self.uploads.connections.waiting(lane)
155    }
156    /// What holds trailing uploads now (§12.3, §17.4, §17.9): the app's
157    /// pause, a self-replacement's pause of this device's writes, or a
158    /// metered network while the app moves files only on unmetered ones.
159    pub(crate) fn trailing_hold(&self) -> Option<TrailingHold> {
160        let uploads = &self.uploads;
161        if uploads.paused() {
162            Some(TrailingHold::Paused)
163        } else if uploads.writes_paused() {
164            Some(TrailingHold::MemberKeysChanging)
165        } else if self.metered_holds(false) {
166            Some(TrailingHold::Metered)
167        } else {
168            None
169        }
170    }
171    /// How many app retries have been asked.
172    pub(crate) fn retries_asked(&self) -> u64 {
173        self.uploads.retries_asked()
174    }
175    /// A trailing upload's completion was refused: the pause holds the lane
176    /// until a read of the queue finds it ended.
177    pub(crate) fn writes_were_paused(&self) {
178        self.uploads.set_writes_paused(true);
179    }
180    /// Whether anything holds trailing uploads now.
181    pub(crate) fn trailing_held(&self) -> bool {
182        self.trailing_hold().is_some()
183    }
184    /// Take the app's pause as the owner's copy.
185    pub(crate) fn set_paused(&self, paused: bool) {
186        self.uploads.set_paused(paused);
187    }
188    /// Count an app retry asked, returning how many were asked before it.
189    pub(crate) fn retry_asked(&self) -> u64 {
190        self.uploads.retry_asked()
191    }
192    /// `hold_change`, for a run; a test hears each wait for it.
193    pub(crate) async fn lock_hold_change(&self) -> tokio::sync::MutexGuard<'_, ()> {
194        self.uploads.lock_hold_change().await
195    }
196    /// `hold_change`, for a setting's change on its write's blocking thread.
197    pub(super) fn hold_change_blocking(&self) -> tokio::sync::MutexGuard<'_, ()> {
198        self.uploads.hold_change_blocking()
199    }
200    /// Wait until a setting's change or a run finds `hold_change` held and
201    /// waits, after this call.
202    #[cfg(test)]
203    pub(crate) fn change_waits_from_now(&self) -> impl std::future::Future<Output = ()> {
204        self.uploads.change_waits_from_now()
205    }
206    /// Hold the next upload run once it has read the persisted settings,
207    /// until the test resumes it.
208    #[cfg(test)]
209    pub(crate) fn hold_after_settings_read(
210        &self,
211        gate: (tokio::sync::oneshot::Sender<()>, tokio::sync::oneshot::Receiver<()>),
212    ) {
213        self.uploads.hold_after_settings_read(gate);
214    }
215    /// The gate a test set, if any, for the run that has read the settings.
216    #[cfg(test)]
217    pub(crate) fn take_settings_read_gate(
218        &self,
219    ) -> Option<(tokio::sync::oneshot::Sender<()>, tokio::sync::oneshot::Receiver<()>)> {
220        self.uploads.take_settings_read_gate()
221    }
222    /// Read whether a self-replacement pauses this device's writes.
223    pub(crate) async fn read_writes_paused(&self) -> Result<(), coven_database::DbError> {
224        let paused = self.database.writes_paused().await?;
225        self.uploads.set_writes_paused(paused);
226        Ok(())
227    }
228}