| 13 | 13 | | //! for other paths is another entry. |
| 14 | 14 | | //! - A key is written once in its scope and version. In each scope in |
| 15 | 15 | | //! turn, a restore finds its key exactly, else the newest entry whose key |
| 16 | | − | //! starts with one of its restore keys. |
| 16 | + | //! starts with its key, else with each of its restore keys in order |
| 17 | + | //! (`prefixes`), as GitHub's cache does. |
| 17 | 18 | | //! - An entry is at most `CACHE_MAX_ENTRY_BYTES`. A repository's entries |
| 18 | 19 | | //! hold at most `CACHE_REPO_QUOTA_BYTES` together: saving past it evicts |
| 19 | 20 | | //! the entries restored longest ago. |
| ⋯ |
| 103 | 104 | | (gb_months * CACHE_MICROS_PER_GB_MONTH as f64).ceil() as i64 |
| 104 | 105 | | } |
| 105 | 106 | | |
| 107 | + | /// The prefixes a restore tries in each scope once its key has no exact |
| 108 | + | /// match, in order: the key itself, then its restore keys. Blank ones and |
| 109 | + | /// repeats are dropped. |
| 110 | + | pub(crate) fn prefixes<'a>(key: &'a str, restore: &'a [String]) -> Vec<&'a str> { |
| 111 | + | let mut out: Vec<&str> = Vec::new(); |
| 112 | + | for prefix in std::iter::once(key).chain(restore.iter().map(String::as_str)).map(str::trim) { |
| 113 | + | if !prefix.is_empty() && !out.contains(&prefix) { |
| 114 | + | out.push(prefix); |
| 115 | + | } |
| 116 | + | } |
| 117 | + | out |
| 118 | + | } |
| 119 | + | |
| 106 | 120 | | /// Where a job's cache entries are found and saved: its repository, and in |
| 107 | 121 | | /// it the refs it restores from, in order, and the one it saves to. |
| 108 | 122 | | pub(crate) struct CacheScope { |
| ⋯ |
| 175 | 189 | | if found.is_some() { |
| 176 | 190 | | break; |
| 177 | 191 | | } |
| 178 | | − | for prefix in a.restore.iter().map(|p| p.trim()).filter(|p| !p.is_empty()) { |
| 192 | + | for prefix in prefixes(&a.key, &a.restore) { |
| 179 | 193 | | found = self |
| 180 | 194 | | .db |
| 181 | 195 | | .prepare( |
| ⋯ |
| 549 | 563 | | } |
| 550 | 564 | | |
| 551 | 565 | | #[test] |
| 566 | + | fn a_restore_tries_its_key_as_a_prefix_before_its_restore_keys() { |
| 567 | + | let restore = vec!["cargo-Linux-1.99.0-".to_owned(), " ".to_owned(), "cargo-".to_owned(), "cargo-".to_owned()]; |
| 568 | + | assert_eq!(prefixes("cargo-Linux-1.99.0-abc", &restore), ["cargo-Linux-1.99.0-abc", "cargo-Linux-1.99.0-", "cargo-"]); |
| 569 | + | assert_eq!(prefixes("k", &[]), ["k"]); |
| 570 | + | } |
| 571 | + | |
| 572 | + | #[test] |
| 552 | 573 | | fn keys_are_checked() { |
| 553 | 574 | | assert!(valid_key("cargo-Linux-abc123")); |
| 554 | 575 | | assert!(!valid_key("")); |