Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/remote_settings/dumps/main/regions.timestamp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1600363002708
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1763049497744
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1764082724032
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1757010621729
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1755604678567
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1761148716130
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1749069444811
49 changes: 35 additions & 14 deletions components/remote_settings/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,17 @@ impl<C: ApiClient> RemoteSettingsClient<C> {
&self.collection_name
}

fn load_packaged_timestamp(&self) -> Option<u64> {
// Using the macro generated `get_packaged_timestamp` in macros.rs
Self::get_packaged_timestamp(&self.collection_name)
}

fn load_packaged_data(&self) -> Option<CollectionData> {
// Using the macro generated `get_packaged_data` in macros.rs
Self::get_packaged_data(&self.collection_name)
.and_then(|data| serde_json::from_str(data).ok())
let str_data = Self::get_packaged_data(&self.collection_name)?;
let data: CollectionData = serde_json::from_str(str_data).ok()?;
debug_assert_eq!(data.timestamp, self.load_packaged_timestamp().unwrap());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of debug_assert_eq! :)

Some(data)
}

fn load_packaged_attachment(&self, filename: &str) -> Option<(&'static [u8], &'static str)> {
Expand All @@ -241,30 +248,44 @@ impl<C: ApiClient> RemoteSettingsClient<C> {
.collect()
}

/// Returns the parsed packaged data, but only if it's newer than the data we have
/// in storage. This avoids parsing the packaged data if we won't use it.
fn get_packaged_data_if_newer(
&self,
storage: &mut Storage,
collection_url: &str,
) -> Result<Option<CollectionData>> {
let packaged_ts = self.load_packaged_timestamp();
let storage_ts = storage.get_last_modified_timestamp(collection_url)?;
let packaged_is_newer = match (packaged_ts, storage_ts) {
(Some(packaged_ts), Some(storage_ts)) => packaged_ts > storage_ts,
(Some(_), None) => true, // no storage data
(None, _) => false, // no packaged data
};

if packaged_is_newer {
Ok(self.load_packaged_data())
} else {
Ok(None)
}
}

/// Get the current set of records.
///
/// If records are not present in storage this will normally return None. Use `sync_if_empty =
/// true` to change this behavior and perform a network request in this case.
pub fn get_records(&self, sync_if_empty: bool) -> Result<Option<Vec<RemoteSettingsRecord>>> {
let mut inner = self.inner.lock();
let collection_url = inner.api_client.collection_url();
let is_prod = inner.api_client.is_prod_server()?;
let packaged_data = if is_prod {
self.load_packaged_data()
} else {
None
};

// Case 1: The packaged data is more recent than the cache
//
// This happens when there's no cached data or when we get new packaged data because of a
// product update
if let Some(packaged_data) = packaged_data {
let cached_timestamp = inner
.storage
.get_last_modified_timestamp(&collection_url)?
.unwrap_or(0);
if packaged_data.timestamp > cached_timestamp {
if inner.api_client.is_prod_server()? {
if let Some(packaged_data) =
self.get_packaged_data_if_newer(&mut inner.storage, &collection_url)?
{
// Remove previously cached data (packaged data does not have tombstones like diff responses do).
inner.storage.empty()?;
// Insert new packaged data.
Expand Down
20 changes: 20 additions & 0 deletions components/remote_settings/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ macro_rules! packaged_collections {
_ => None,
}
}

/// Get just the timestamp, which is stored separately. This allows
/// checking which data is newer without paying the cost of parsing
/// the full packaged JSON.
fn get_packaged_timestamp(collection_name: &str) -> Option<u64> {
match collection_name {
$($collection => {
let timestamp_str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/dumps/",
$bucket,
"/",
$collection,
".timestamp"
));
timestamp_str.trim().parse().ok()
}),*
_ => None,
}
}
};
}

Expand Down
4 changes: 4 additions & 0 deletions examples/remote-settings-cli/src/dump/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,10 @@ impl CollectionDownloader {
}
std::fs::write(&dumps_path, serde_json::to_string_pretty(&data)?)?;

// Write timestamp file for fast timestamp checking without JSON parsing
let timestamp_path = dumps_path.with_extension("timestamp");
std::fs::write(&timestamp_path, data.timestamp.to_string())?;

// Count attachments needing updates
for record in &data.data {
if let Some(attachment) = record.get("attachment") {
Expand Down