Skip to content

Commit 51025c5

Browse files
committed
Refactor: Deprecate changemap
1 parent e47a3eb commit 51025c5

File tree

11 files changed

+136
-89
lines changed

11 files changed

+136
-89
lines changed

qb-core/src/change.rs

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
//! This module provides primitives for working with changes applied
44
//! to a filesystem.
55
6-
use std::collections::HashMap;
6+
use std::{collections::HashMap, fmt};
77

88
use bitcode::{Decode, Encode};
9+
use itertools::Itertools;
910
use serde::{Deserialize, Serialize};
1011

1112
use crate::{diff::QBDiff, path::QBResource, time::QBTimeStampUnique};
@@ -19,6 +20,19 @@ pub struct QBChange {
1920
pub kind: QBChangeKind,
2021
}
2122

23+
impl fmt::Display for QBChange {
24+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25+
write!(f, "{} {:?}", self.timestamp, self.kind)
26+
}
27+
}
28+
29+
impl QBChange {
30+
/// Construct a new change.
31+
pub fn new(timestamp: QBTimeStampUnique, kind: QBChangeKind) -> Self {
32+
Self { timestamp, kind }
33+
}
34+
}
35+
2236
/// The kind of change.
2337
#[derive(Encode, Decode, Serialize, Deserialize, Debug, Clone)]
2438
pub enum QBChangeKind {
@@ -61,14 +75,15 @@ impl QBChangeKind {
6175
}
6276

6377
/// This struct is a map which stores a collection of changes for each resource.
64-
#[derive(Encode, Decode, Serialize, Deserialize, Debug, Default)]
78+
#[derive(Encode, Decode, Serialize, Deserialize, Debug, Default, Clone)]
6579
pub struct QBChangeMap {
6680
changes: HashMap<QBResource, Vec<QBChange>>,
81+
head: QBTimeStampUnique,
6782
}
6883

6984
impl QBChangeMap {
7085
/// Gets the changes since the timestamp.
71-
pub fn since_cloned(&self, since: QBTimeStampUnique) -> QBChangeMap {
86+
pub fn since_cloned(&self, since: &QBTimeStampUnique) -> QBChangeMap {
7287
// iterator magic
7388
let changes = self
7489
.changes
@@ -78,19 +93,64 @@ impl QBChangeMap {
7893
resource.clone(),
7994
entries
8095
.into_iter()
81-
.filter(|e| e.timestamp > since)
96+
.filter(|e| &e.timestamp > since)
8297
.cloned()
8398
.collect::<Vec<_>>(),
8499
)
85100
})
86101
.filter(|(_, entries)| !entries.is_empty())
87102
.collect::<HashMap<_, _>>();
88103

89-
QBChangeMap { changes }
104+
QBChangeMap {
105+
changes,
106+
head: self.head.clone(),
107+
}
108+
}
109+
110+
/// Gets the changes since the timestamp.
111+
pub fn since(&mut self, since: &QBTimeStampUnique) -> QBChangeMap {
112+
// iterator magic
113+
let changes = self
114+
.changes
115+
.iter_mut()
116+
.filter_map(|(resource, entries)| {
117+
Some((
118+
resource.clone(),
119+
entries
120+
.drain(entries.iter().position(|e| &e.timestamp > since)?..)
121+
.collect(),
122+
))
123+
})
124+
.collect::<HashMap<_, _>>();
125+
126+
QBChangeMap {
127+
changes,
128+
head: self.head.clone(),
129+
}
130+
}
131+
132+
/// Returns whether this changemap is empty.
133+
#[inline(always)]
134+
pub fn is_empty(&self) -> bool {
135+
self.changes.is_empty()
136+
}
137+
138+
/// Iterate over the changes.
139+
pub fn iter(&self) -> impl Iterator<Item = (&QBResource, &QBChange)> {
140+
self.changes
141+
.iter()
142+
.map(|(resource, entries)| entries.into_iter().map(move |change| (resource, change)))
143+
.flatten()
144+
.sorted_by(|a, b| a.1.timestamp.cmp(&b.1.timestamp))
145+
}
146+
147+
/// Return the head of this changemap (the last change).
148+
pub fn head(&self) -> &QBTimeStampUnique {
149+
&self.head
90150
}
91151

92152
/// Gets the changes for a given resource from this changemap.
93-
#[inline]
153+
#[inline(always)]
94154
pub fn entries(&mut self, resource: QBResource) -> &mut Vec<QBChange> {
95155
self.changes.entry(resource).or_default()
96156
}
@@ -102,12 +162,12 @@ impl QBChangeMap {
102162
}
103163
}
104164

105-
#[inline]
165+
#[inline(always)]
106166
fn _sort(entries: &mut [QBChange]) {
107167
entries.sort_by(|a, b| a.timestamp.cmp(&b.timestamp));
108168
}
109169

110-
#[inline]
170+
#[inline(always)]
111171
fn _sort_borrowed(entries: &mut [&QBChange]) {
112172
entries.sort_by(|a, b| a.timestamp.cmp(&b.timestamp));
113173
}
@@ -120,7 +180,7 @@ impl QBChangeMap {
120180
}
121181
}
122182

123-
#[inline]
183+
#[inline(always)]
124184
fn _minify(entries: &mut Vec<QBChange>) {
125185
let mut remove_until = 0;
126186

qb-core/src/fs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
hash::QBHash,
2323
ignore::{QBIgnoreMap, QBIgnoreMapBuilder},
2424
path::qbpaths::{
25-
INTERNAL_CHANGELOG, INTERNAL_DEVICES, INTERNAL_FILETABLE, INTERNAL_FILETREE,
25+
INTERNAL_CHANGEMAP, INTERNAL_DEVICES, INTERNAL_FILETABLE, INTERNAL_FILETREE,
2626
INTERNAL_IGNORE,
2727
},
2828
path::{qbpaths, QBPath, QBPathError},
@@ -87,7 +87,7 @@ impl QBFS {
8787
let ignore_builder: QBIgnoreMapBuilder = wrapper.dload(INTERNAL_IGNORE.as_ref()).await;
8888
let ignore = ignore_builder.build(&table);
8989
let devices = wrapper.dload(INTERNAL_DEVICES.as_ref()).await;
90-
let changelog = wrapper.dload(INTERNAL_CHANGELOG.as_ref()).await;
90+
let changelog = wrapper.dload(INTERNAL_CHANGEMAP.as_ref()).await;
9191

9292
println!("loaded {}", ignore);
9393

@@ -205,7 +205,7 @@ impl QBFS {
205205
/// Save changelog to file system.
206206
pub async fn save_changelog(&self) -> QBFSResult<()> {
207207
self.wrapper
208-
.save(qbpaths::INTERNAL_CHANGELOG.as_ref(), &self.changelog)
208+
.save(qbpaths::INTERNAL_CHANGEMAP.as_ref(), &self.changelog)
209209
.await
210210
}
211211

qb-core/src/path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub mod qbpaths {
2424
/// the directory where quixbyte stores internal files
2525
pub static ref INTERNAL: QBPath = unsafe { QBPath::new("/.qb") };
2626
/// the internal changelog path
27-
pub static ref INTERNAL_CHANGELOG: QBPath = unsafe { QBPath::new("/.qb/changelog") };
27+
pub static ref INTERNAL_CHANGEMAP: QBPath = unsafe { QBPath::new("/.qb/changemap") };
2828
/// the internal filetree path
2929
pub static ref INTERNAL_FILETREE: QBPath = unsafe { QBPath::new("/.qb/filetree") };
3030
/// the internal filetable path

qb-core/src/time.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88
fmt,
99
time::{SystemTime, UNIX_EPOCH},
1010
};
11-
use time::OffsetDateTime;
11+
use time::{macros::format_description, OffsetDateTime};
1212

1313
use crate::device::QBDeviceId;
1414

@@ -21,7 +21,8 @@ pub struct QBTimeStamp(u64);
2121
impl fmt::Display for QBTimeStamp {
2222
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2323
let datetime = OffsetDateTime::from_unix_timestamp(self.0 as i64).unwrap();
24-
write!(f, "{}", datetime)
24+
let ft = format_description!("[day]-[month repr:short]-[year] [hour]:[minute]:[second]");
25+
write!(f, "{}", datetime.format(ft).unwrap())
2526
}
2627
}
2728

qb-daemon/src/daemon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! which handles controlling tasks and processes the control
55
//! requests sent by those. It manages the [master].
66
7-
use qb_core::{common::qbpaths::INTERNAL_CONFIG, fs::wrapper::QBFSWrapper};
7+
use qb_core::{fs::wrapper::QBFSWrapper, path::qbpaths::INTERNAL_CONFIG};
88
use std::{
99
collections::{HashMap, HashSet},
1010
future::Future,

qb-daemon/src/master.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77
use std::{collections::HashMap, future::Future, pin::Pin, rc::Rc};
88

99
use qb_core::{
10-
change::log::QBChangelog,
11-
common::{
12-
device::{QBDeviceId, QBDeviceTable},
13-
qbpaths::{INTERNAL_CHANGELOG, INTERNAL_DEVICES},
14-
},
10+
change::QBChangeMap,
11+
device::{QBDeviceId, QBDeviceTable},
1512
fs::wrapper::QBFSWrapper,
13+
path::qbpaths::{INTERNAL_CHANGEMAP, INTERNAL_DEVICES},
1614
};
1715
use qb_ext::{
1816
hook::{QBHChannel, QBHContext, QBHHostMessage, QBHId, QBHSlaveMessage},
@@ -95,7 +93,7 @@ pub struct QBMaster {
9593
pub hook_rx: mpsc::Receiver<(QBHId, QBHSlaveMessage)>,
9694
hook_tx: mpsc::Sender<(QBHId, QBHSlaveMessage)>,
9795
devices: QBDeviceTable,
98-
changelog: QBChangelog,
96+
changemap: QBChangeMap,
9997
wrapper: QBFSWrapper,
10098
}
10199

@@ -110,7 +108,7 @@ impl QBMaster {
110108

111109
wrapper.init().await.unwrap();
112110
let devices = wrapper.dload(INTERNAL_DEVICES.as_ref()).await;
113-
let changelog = wrapper.dload(INTERNAL_CHANGELOG.as_ref()).await;
111+
let changemap = wrapper.dload(INTERNAL_CHANGEMAP.as_ref()).await;
114112

115113
QBMaster {
116114
interfaces: HashMap::new(),
@@ -120,7 +118,7 @@ impl QBMaster {
120118
hook_rx,
121119
hook_tx,
122120
devices,
123-
changelog,
121+
changemap,
124122
wrapper,
125123
}
126124
}
@@ -132,7 +130,7 @@ impl QBMaster {
132130
.await
133131
.unwrap();
134132
self.wrapper
135-
.save(INTERNAL_CHANGELOG.as_ref(), &self.changelog)
133+
.save(INTERNAL_CHANGEMAP.as_ref(), &self.changemap)
136134
.await
137135
.unwrap();
138136
}
@@ -221,18 +219,19 @@ impl QBMaster {
221219
let handle_common = self.devices.get_common(&device_id);
222220

223221
match msg {
224-
QBIMessage::Sync { common, changes } => {
222+
QBIMessage::Sync { common, .. } => {
225223
assert!(handle_common == &common);
226224

227225
// Find local changes
228-
let local_entries = self.changelog.after(&common).unwrap();
226+
let local_entries = self.changemap.since(&common);
229227

230228
// Apply changes to changelog
231-
let (mut entries, _) = QBChangelog::merge(local_entries.clone(), changes).unwrap();
232-
self.changelog.append(&mut entries);
229+
// TODO: merging
230+
//let (mut entries, _) = QBChangelog::merge(local_entries.clone(), changes).unwrap();
231+
//self.changemap.append(&mut entries);
233232

234-
// Negotiate a new common hash
235-
let new_common = self.changelog.head();
233+
// find the new common hash
234+
let new_common = self.changemap.head().clone();
236235
self.devices.set_common(&device_id, new_common);
237236

238237
// Send sync to remote
@@ -389,7 +388,7 @@ impl QBMaster {
389388
}
390389

391390
let handle_common = self.devices.get_common(&device_id);
392-
let changes = self.changelog.after_cloned(handle_common).unwrap();
391+
let changes = self.changemap.since_cloned(handle_common);
393392

394393
// skip if no changes to sync
395394
if changes.is_empty() {

qb-ext/src/interface.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ use serde::{Deserialize, Serialize};
2222
use std::fmt;
2323
use std::future::Future;
2424

25-
use qb_core::{
26-
change::QBChange,
27-
common::{device::QBDeviceId, hash::QBHash},
28-
};
25+
use qb_core::{change::QBChangeMap, device::QBDeviceId, time::QBTimeStampUnique};
2926

3027
use crate::QBChannel;
3128

@@ -89,14 +86,14 @@ pub enum QBIMessage {
8986
/// change gets updated (synchronization)
9087
Common {
9188
/// hash that points to the common change
92-
common: QBHash,
89+
common: QBTimeStampUnique,
9390
},
9491
/// synchronize
9592
Sync {
9693
/// the common hash that was used for creating the changes vector
97-
common: QBHash,
94+
common: QBTimeStampUnique,
9895
/// a vector describing the changes
99-
changes: Vec<QBChange>,
96+
changes: QBChangeMap,
10097
},
10198
/// An interface might not be properly initialized
10299
/// at attachment and we might not even know the Id
@@ -111,13 +108,11 @@ pub enum QBIMessage {
111108
impl fmt::Display for QBIMessage {
112109
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113110
match &self {
114-
QBIMessage::Sync {
115-
common,
116-
changes: entries,
117-
} => {
111+
QBIMessage::Sync { common, changes } => {
118112
writeln!(f, "QBI_MSG_SYNC common: {}", common)?;
119-
for entry in entries {
113+
for (resource, entry) in changes.iter() {
120114
fmt::Display::fmt(entry, f)?;
115+
fmt::Display::fmt(resource, f)?;
121116
writeln!(f)?;
122117
}
123118
Ok(())

0 commit comments

Comments
 (0)