fix(build): give the existence cache a per-minor view of the slot #191
2 changed files with 59 additions and 3 deletions
|
|
@ -189,8 +189,42 @@ sprintf(
|
||||||
# Read pre-computed S3 listing from install-deps step
|
# Read pre-computed S3 listing from install-deps step
|
||||||
# This avoids loading s3fs/reticulate/Python in the build container,
|
# This avoids loading s3fs/reticulate/Python in the build container,
|
||||||
# saving significant memory for the dependency-installer subprocesses
|
# saving significant memory for the dependency-installer subprocesses
|
||||||
s3_cache <- readRDS("/mnt/cache/packages/s3_cache.rds")
|
s3_cache_paths <- readRDS("/mnt/cache/packages/s3_cache.rds")
|
||||||
sprintf("S3 cache: %s files", length(s3_cache))
|
|
||||||
|
# The cache is stored as paths relative to the slot, so a pass can select the
|
||||||
|
# objects that belong to it. `build_binary_package()` compares basenames, which
|
||||||
|
# cannot distinguish `4.4/curl_1.0.tar.gz` from `curl_1.0.tar.gz`, so the choice
|
||||||
|
# has to be made here where the running R minor is known.
|
||||||
|
#
|
||||||
|
# Getting this wrong is expensive in both directions: hand it everything and a
|
||||||
|
# per-minor pass believes the flat slot's binaries are its own and builds
|
||||||
|
# nothing; hand it nothing and it rebuilds what it already has. amd64/resolute
|
||||||
|
# recompiled 8683 packages that way.
|
||||||
|
select_cache_for_pass <- function(paths, sensitive_only, r_minor) {
|
||||||
|
# A cache written before this change holds bare basenames. Filtering those by
|
||||||
|
# path would select nothing and trigger a full rebuild, so use them as they
|
||||||
|
# are; #190's staleness check replaces it on the next pipeline anyway.
|
||||||
|
if (!any(grepl("/", paths, fixed = TRUE))) {
|
||||||
|
message("S3 cache is in the legacy basename format; using it unfiltered.")
|
||||||
|
return(paths)
|
||||||
|
}
|
||||||
|
in_minor <- grepl(sprintf("^%s/", r_minor), paths)
|
||||||
|
if (sensitive_only) {
|
||||||
|
basename(paths[in_minor])
|
||||||
|
} else {
|
||||||
|
# The primary pass writes the flat slot. Archive/ counts as present there:
|
||||||
|
# those are versions built and later superseded.
|
||||||
|
basename(paths[!grepl("^[0-9]+\\.[0-9]+/", paths)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s3_cache <- select_cache_for_pass(s3_cache_paths, sensitive_only, r_minor)
|
||||||
|
sprintf(
|
||||||
|
"S3 cache: %s files (%s of %s objects apply to this pass)",
|
||||||
|
length(s3_cache),
|
||||||
|
length(s3_cache),
|
||||||
|
length(s3_cache_paths)
|
||||||
|
)
|
||||||
|
|
||||||
n <- nrow(chunk)
|
n <- nrow(chunk)
|
||||||
mapply(
|
mapply(
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,28 @@ source_served <- tryCatch(
|
||||||
)
|
)
|
||||||
|
|
||||||
binary_cache <- setdiff(file_names, source_served)
|
binary_cache <- setdiff(file_names, source_served)
|
||||||
|
|
||||||
|
# The existence cache and the candidate list need different views of the same
|
||||||
|
# listing, and conflating them is what made this wrong in both directions.
|
||||||
|
#
|
||||||
|
# The candidate list must ignore per-minor objects, or a package present under
|
||||||
|
# one minor prunes itself from every other minor's work (#189). The existence
|
||||||
|
# cache must NOT ignore them, or `build_binary_package()` is told nothing is
|
||||||
|
# present under any minor and recompiles the lot: amd64/resolute recompiled
|
||||||
|
# 8683 packages it had already built, reporting "already exists in S3" three
|
||||||
|
# times.
|
||||||
|
#
|
||||||
|
# So the cache keeps the path relative to the slot, and `build-all.R` selects
|
||||||
|
# the part that matches the pass it is running: the flat slot for the primary,
|
||||||
|
# `<minor>/` for a per-minor pass.
|
||||||
|
contrib_prefix <- sprintf(
|
||||||
|
"devxy-rpkgs-binaries/%s/%s/latest/src/contrib/",
|
||||||
|
arch,
|
||||||
|
codename
|
||||||
|
)
|
||||||
|
relative_paths <- sub(contrib_prefix, "", s3_pkgs, fixed = TRUE)
|
||||||
|
source_basenames <- source_served
|
||||||
|
existence_cache <- relative_paths[!basename(relative_paths) %in% source_basenames]
|
||||||
cat(sprintf(
|
cat(sprintf(
|
||||||
"S3 cache: %d objects, %d served as CRAN source, %d usable binaries\n",
|
"S3 cache: %d objects, %d served as CRAN source, %d usable binaries\n",
|
||||||
length(file_names),
|
length(file_names),
|
||||||
|
|
@ -186,7 +208,7 @@ cat(sprintf(
|
||||||
# Save the S3 file listing for the build step to use as s3_package_cache.
|
# Save the S3 file listing for the build step to use as s3_package_cache.
|
||||||
# This avoids loading s3fs/reticulate in the build container, saving memory for
|
# This avoids loading s3fs/reticulate in the build container, saving memory for
|
||||||
# the dependency-installer subprocesses
|
# the dependency-installer subprocesses
|
||||||
saveRDS(binary_cache, "/mnt/cache/packages/s3_cache.rds")
|
saveRDS(existence_cache, "/mnt/cache/packages/s3_cache.rds")
|
||||||
# Built from the filtered listing, not the raw one: `s3_dt` is subtracted from
|
# Built from the filtered listing, not the raw one: `s3_dt` is subtracted from
|
||||||
# the build list below, so a source fallback left in here would exclude the very
|
# the build list below, so a source fallback left in here would exclude the very
|
||||||
# package that needs building.
|
# package that needs building.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue