Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use LayerMap::replace in eviction #3544

Merged
merged 6 commits into from
Feb 7, 2023
Merged
Changes from 5 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
52 changes: 47 additions & 5 deletions pageserver/src/tenant/timeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,15 +867,26 @@ impl Timeline {
Ok(Some(true))
}

/// Evicts one layer as in replaces a downloaded layer with a remote layer
///
/// Returns:
/// - `Ok(Some(true))` when the layer was replaced
/// - `Ok(Some(false))` when the layer was found, but no changes were made
/// - evictee was not yet downloaded
/// - layermap replacement failed
/// - `Ok(None)` when the layer is not found
pub async fn evict_layer(&self, layer_file_name: &str) -> anyhow::Result<Option<bool>> {
use super::layer_map::Replacement;

let Some(local_layer) = self.find_layer(layer_file_name) else { return Ok(None) };
if local_layer.is_remote_layer() {
return Ok(Some(false));
}
let Some(remote_client) = &self.remote_client else { return Ok(Some(false)) };

// ensure the current layer is uploaded for sure
remote_client
self.remote_client
.as_ref()
.ok_or_else(|| anyhow::anyhow!("remote storage not configured; cannot evict"))?
.wait_completion()
.await
.context("wait for layer upload ops to complete")?;
Expand Down Expand Up @@ -903,13 +914,43 @@ impl Timeline {
let gc_lock = self.layer_removal_cs.lock().await;
let mut layers = self.layers.write().unwrap();
let mut updates = layers.batch_update();
self.delete_historic_layer(&gc_lock, local_layer, &mut updates)?;
updates.insert_historic(new_remote_layer);

let replaced = match updates.replace_historic(&local_layer, new_remote_layer)? {
koivunej marked this conversation as resolved.
Show resolved Hide resolved
Replacement::Replaced { .. } => {
let layer_size = local_layer.file_size();

if let Err(e) = local_layer.delete() {
error!("failed to remove layer file on evict after replacement: {e:#?}");
}

if let Some(layer_size) = layer_size {
self.metrics.resident_physical_size_gauge.sub(layer_size);
koivunej marked this conversation as resolved.
Show resolved Hide resolved
}

true
}
Replacement::NotFound => {
debug!(evicted=?local_layer, "lost the race to evict layer");
koivunej marked this conversation as resolved.
Show resolved Hide resolved
false
}
Replacement::RemovalBuffered => {
unreachable!("not doing anything else in this batch")
}
Replacement::Unexpected(other) => {
error!(
local_layer.ptr=?Arc::as_ptr(&local_layer),
other.ptr=?Arc::as_ptr(&other),
?other,
"failed to replace");
false
}
};

updates.flush();
drop(layers);
drop(gc_lock);

Ok(Some(true))
Ok(Some(replaced))
}
}

Expand Down Expand Up @@ -3412,6 +3453,7 @@ impl Timeline {
error!(
expected.ptr = ?Arc::as_ptr(&l),
other.ptr = ?Arc::as_ptr(&other),
?other,
"replacing downloaded layer into layermap failed because another layer was found instead of expected"
);
}
Expand Down