Improve logging and comments in GC.

- Print the number of dropped relations, and the number of relations
  encountered overall.

- If a block has only one page version, the latest one, don't count it as
  a "truncated" version history. Only count pages for which we actually
  removed some old versions.

- Change "last" to "latest" in variable names and comments. "Last" could
  be interpreted as "oldest", but here it means "newest".

- Add a comment noting that the GC code depends on get_page_at_lsn_nowait
  to store the materialized page version in the repository.

- Change "last" to "latest" in variable names for clarity. "Last" could
  be interpreted as the oldest, but here it means newest.
This commit is contained in:
Heikki Linnakangas
2021-06-28 15:42:07 +03:00
parent cb2ddf06d0
commit 0dd46061a8

View File

@@ -534,6 +534,18 @@ impl Timeline for ObjectTimeline {
}
}
///
/// Result of performing GC
///
#[derive(Default)]
struct GcResult {
n_relations: u64,
truncated: u64,
deleted: u64,
dropped: u64,
elapsed: Duration,
}
impl ObjectTimeline {
fn gc_iteration(&self, horizon: u64) -> Result<()> {
let last_lsn = self.get_last_valid_lsn();
@@ -542,41 +554,43 @@ impl ObjectTimeline {
if let Some(horizon) = last_lsn.checked_sub(horizon) {
// WAL is large enough to perform GC
let now = Instant::now();
let mut truncated = 0u64;
let mut deleted = 0u64;
let mut result: GcResult = Default::default();
// Iterate through all relations
for rels in &self.obj_store.list_rels(self.timelineid, 0, 0, last_lsn)? {
let rel = *rels;
let mut last_version = true;
let key = relation_size_key(self.timelineid, rel);
let mut max_size = 0u32;
let mut relation_dropped = false;
result.n_relations += 1;
// Process relation metadata versions
let mut latest_version = true;
for vers in self.obj_store.object_versions(&key, horizon)? {
let lsn = vers.0;
let rel_meta = RelationSizeEntry::des(&vers.1)?;
// If relation is dropped at the horizon,
// we can remove all its versions including last (Unlink)
// we can remove all its versions including latest (Unlink)
match rel_meta {
RelationSizeEntry::Size(size) => max_size = max(max_size, size),
RelationSizeEntry::Unlink => {
if last_version {
if latest_version {
relation_dropped = true;
info!("Relation {:?} dropped", rels);
result.dropped += 1;
}
}
}
if last_version {
last_version = false;
// preserve latest version, unless the relation was dropped completely.
if latest_version {
latest_version = false;
if !relation_dropped {
// preserve last version
continue;
}
}
self.obj_store.unlink(&key, lsn)?;
deleted += 1;
result.deleted += 1;
}
// Now process all relation blocks
for blknum in 0..max_size {
@@ -585,25 +599,30 @@ impl ObjectTimeline {
timeline: self.timelineid,
tag: ObjectTag::RelationBuffer(buf_tag),
};
last_version = true;
for vers in self.obj_store.object_versions(&key, horizon)? {
let lsn = vers.0;
if last_version {
last_version = false;
truncated += 1;
let mut latest_version = true;
let mut deleted_page_versions = 0;
for (lsn, _val) in self.obj_store.object_versions(&key, horizon)? {
// Preserve and materialize latest version before deleting all preceding versions.
// We let get_page_at_lsn_nowait() do the materialization.
if latest_version {
latest_version = false;
if !relation_dropped {
// preserve and materialize last version before deleting all preceeding
self.get_page_at_lsn_nowait(buf_tag, lsn)?;
continue;
}
}
self.obj_store.unlink(&key, lsn)?;
deleted += 1;
deleted_page_versions += 1;
}
if deleted_page_versions > 0 && !relation_dropped {
result.truncated += 1;
}
result.deleted += deleted_page_versions;
}
}
info!("Garbage collection completed in {:?}: {} version histories truncated, {} versions deleted",
now.elapsed(), &truncated, &deleted);
result.elapsed = now.elapsed();
info!("Garbage collection completed in {:?}: {} relations inspected, {} version histories truncated, {} versions deleted, {} relations dropped",
result.elapsed, &result.n_relations, &result.truncated, &result.deleted, &result.dropped);
}
Ok(())
}
@@ -629,6 +648,10 @@ impl ObjectTimeline {
let (base_img, records) = self.collect_records_for_apply(tag, lsn)?;
page_img = self.walredo_mgr.request_redo(tag, lsn, base_img, records)?;
// Garbage collection assumes that we remember the materialized page
// version. Otherwise we could opt to not do it, with the downside that
// the next GetPage@LSN call of the same page version would have to
// redo the WAL again.
self.put_page_image(tag, lsn, page_img.clone())?;
}
}