Skip to content

Commit cf09f9d

Browse files
committed
Auto merge of #513 - Zeegomo:refactor-crates, r=pietroalbini
Refactor crates Some changes especially useful for future updates: * Save sha inside `Crate` enum instead of saving it into db. * Simplify `Crate` representation inside db
2 parents 8911f03 + c019cf0 commit cf09f9d

File tree

16 files changed

+311
-191
lines changed

16 files changed

+311
-191
lines changed

src/actions/experiments/create.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl Action for CreateExperiment {
8181
let skipped = !self.ignore_blacklist && ctx.config.should_skip(krate);
8282
transaction.execute(
8383
"INSERT INTO experiment_crates (experiment, crate, skipped, status) VALUES (?1, ?2, ?3, ?4);",
84-
&[&self.name, &::serde_json::to_string(&krate)?, &skipped, &Status::Queued.to_string()],
84+
&[&self.name, &krate.id(), &skipped, &Status::Queued.to_string()],
8585
)?;
8686
}
8787

@@ -188,7 +188,7 @@ mod tests {
188188
&[&ex],
189189
|row| {
190190
let krate: String = row.get("crate");
191-
serde_json::from_str(&krate).unwrap()
191+
krate.parse().unwrap()
192192
},
193193
)
194194
.unwrap();

src/actions/experiments/edit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl Action for EditExperiment {
101101
VALUES (?1, ?2, ?3, ?4);",
102102
&[
103103
&self.name,
104-
&::serde_json::to_string(&krate)?,
104+
&krate.id(),
105105
&(!ex.ignore_blacklist && ctx.config.should_skip(krate)),
106106
&Status::Queued.to_string(),
107107
],
@@ -256,7 +256,7 @@ mod tests {
256256
&[&ex],
257257
|row| {
258258
let krate: String = row.get("crate");
259-
serde_json::from_str(&krate).unwrap()
259+
krate.parse().unwrap()
260260
},
261261
)
262262
.unwrap();

src/agent/api.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::agent::Capabilities;
2-
use crate::crates::{Crate, GitHubRepo};
2+
use crate::crates::Crate;
33
use crate::experiments::Experiment;
44
use crate::prelude::*;
55
use crate::results::TestResult;
@@ -151,7 +151,7 @@ impl AgentApi {
151151
toolchain: &Toolchain,
152152
log: &[u8],
153153
result: TestResult,
154-
shas: &[(GitHubRepo, String)],
154+
version: Option<(&Crate, &Crate)>,
155155
) -> Fallible<()> {
156156
self.retry(|this| {
157157
let _: bool = this
@@ -166,7 +166,7 @@ impl AgentApi {
166166
"log": base64::encode(log),
167167
},
168168
],
169-
"shas": shas,
169+
"version": version
170170
}))
171171
.send()?
172172
.to_api_response()?;

src/agent/results.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
use crate::agent::api::AgentApi;
22
use crate::config::Config;
3-
use crate::crates::{Crate, GitHubRepo};
3+
use crate::crates::Crate;
44
use crate::experiments::Experiment;
55
use crate::prelude::*;
66
use crate::results::{EncodingType, TestResult, WriteResults};
77
use crate::toolchain::Toolchain;
88
use rustwide::logging::{self, LogStorage};
9-
use std::ops::DerefMut;
9+
use std::collections::{hash_map::Entry::Occupied, HashMap};
1010
use std::sync::{Arc, Mutex};
1111

1212
#[derive(Clone)]
1313
pub struct ResultsUploader<'a> {
1414
api: &'a AgentApi,
15-
shas: Arc<Mutex<Vec<(GitHubRepo, String)>>>,
15+
versions: Arc<Mutex<HashMap<Crate, (Crate, bool)>>>,
1616
}
1717

1818
impl<'a> ResultsUploader<'a> {
1919
pub fn new(api: &'a AgentApi) -> Self {
2020
ResultsUploader {
2121
api,
22-
shas: Arc::new(Mutex::new(Vec::new())),
22+
versions: Arc::new(Mutex::new(HashMap::new())),
2323
}
2424
}
2525
}
@@ -35,11 +35,11 @@ impl<'a> WriteResults for ResultsUploader<'a> {
3535
Ok(None)
3636
}
3737

38-
fn record_sha(&self, _ex: &Experiment, repo: &GitHubRepo, sha: &str) -> Fallible<()> {
39-
self.shas
38+
fn update_crate_version(&self, _ex: &Experiment, old: &Crate, new: &Crate) -> Fallible<()> {
39+
self.versions
4040
.lock()
4141
.unwrap()
42-
.push((repo.clone(), sha.to_string()));
42+
.insert(old.clone(), (new.clone(), false));
4343
Ok(())
4444
}
4545

@@ -60,11 +60,35 @@ impl<'a> WriteResults for ResultsUploader<'a> {
6060
let result = logging::capture(&storage, f)?;
6161
let output = storage.to_string();
6262

63-
let shas = ::std::mem::replace(self.shas.lock().unwrap().deref_mut(), Vec::new());
63+
let mut updated = None;
64+
let mut new_version = None;
65+
// This is done to avoid locking versions if record_progress retries in loop
66+
{
67+
let mut versions = self.versions.lock().unwrap();
68+
if let Occupied(mut entry) = versions.entry(krate.clone()) {
69+
let value = entry.get_mut();
70+
71+
if value.1 {
72+
// delete entry if we already processed both toolchains
73+
updated = Some(entry.remove().0);
74+
} else {
75+
updated = Some(value.0.clone());
76+
new_version = updated.as_ref();
77+
// mark we already sent the updated version to the server
78+
value.1 = true;
79+
}
80+
};
81+
}
6482

6583
info!("sending results to the crater server...");
66-
self.api
67-
.record_progress(ex, krate, toolchain, output.as_bytes(), result, &shas)?;
84+
self.api.record_progress(
85+
ex,
86+
updated.as_ref().unwrap_or(krate),
87+
toolchain,
88+
output.as_bytes(),
89+
result,
90+
new_version.map(|new| (krate, new)),
91+
)?;
6892

6993
Ok(result)
7094
}

src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,12 @@ mod tests {
329329
assert!(list.is_quiet(&Crate::GitHub(GitHubRepo {
330330
org: "rust-lang".into(),
331331
name: "rust".into(),
332+
sha: None,
332333
})));
333334
assert!(!list.is_quiet(&Crate::GitHub(GitHubRepo {
334335
org: "rust-lang".into(),
335336
name: "cargo".into(),
337+
sha: None,
336338
})));
337339

338340
assert_eq!(list.chunk_size(), 32);

src/crates/lists.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(crate) trait List {
2727
for krate in &crates {
2828
t.execute(
2929
"INSERT INTO crates (crate, list, loaded_at) VALUES (?1, ?2, ?3);",
30-
&[&::serde_json::to_string(krate)?, &Self::NAME, &now],
30+
&[&krate.id(), &Self::NAME, &now],
3131
)
3232
.with_context(|_| {
3333
format!(
@@ -51,7 +51,7 @@ pub(crate) trait List {
5151
&[&Self::NAME],
5252
|r| {
5353
let raw: String = r.get("crate");
54-
Ok(::serde_json::from_str(&raw)?)
54+
Ok(raw.parse()?)
5555
},
5656
)?;
5757

src/crates/mod.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ impl Crate {
2121
pub(crate) fn id(&self) -> String {
2222
match *self {
2323
Crate::Registry(ref details) => format!("reg/{}/{}", details.name, details.version),
24-
Crate::GitHub(ref repo) => format!("gh/{}/{}", repo.org, repo.name),
24+
Crate::GitHub(ref repo) => {
25+
if let Some(ref sha) = repo.sha {
26+
format!("gh/{}/{}/{}", repo.org, repo.name, sha)
27+
} else {
28+
format!("gh/{}/{}", repo.org, repo.name)
29+
}
30+
}
2531
Crate::Local(ref name) => format!("local/{}", name),
2632
}
2733
}
@@ -54,18 +60,56 @@ impl fmt::Display for Crate {
5460
impl FromStr for Crate {
5561
type Err = ::failure::Error;
5662

63+
// matches with `Crate::id'
5764
fn from_str(s: &str) -> Fallible<Self> {
58-
if s.starts_with("https://github.com/") {
59-
Ok(Crate::GitHub(s.parse()?))
60-
} else if let Some(dash_idx) = s.rfind('-') {
61-
let name = &s[..dash_idx];
62-
let version = &s[dash_idx + 1..];
63-
Ok(Crate::Registry(RegistryCrate {
65+
match s.split('/').collect::<Vec<_>>()[..] {
66+
["reg", name, version] => Ok(Crate::Registry(RegistryCrate {
6467
name: name.to_string(),
6568
version: version.to_string(),
66-
}))
67-
} else {
68-
bail!("crate not found");
69+
})),
70+
["gh", org, name, sha] => Ok(Crate::GitHub(GitHubRepo {
71+
org: org.to_string(),
72+
name: name.to_string(),
73+
sha: Some(sha.to_string()),
74+
})),
75+
["gh", org, name] => Ok(Crate::GitHub(GitHubRepo {
76+
org: org.to_string(),
77+
name: name.to_string(),
78+
sha: None,
79+
})),
80+
["local", name] => Ok(Crate::Local(name.to_string())),
81+
_ => bail!("unexpected crate value"),
82+
}
83+
}
84+
}
85+
86+
#[cfg(test)]
87+
mod tests {
88+
use super::{Crate, GitHubRepo, RegistryCrate};
89+
use std::str::FromStr;
90+
91+
#[test]
92+
fn test_parse() {
93+
macro_rules! test_from_str {
94+
($($str:expr => $rust:expr,)*) => {
95+
$(
96+
// Test parsing from string to rust
97+
assert_eq!(Crate::from_str($str).unwrap(), $rust);
98+
99+
// Test dumping from rust to string
100+
assert_eq!(&$rust.id(), $str);
101+
102+
// Test dumping from rust to string to rust
103+
assert_eq!(Crate::from_str($rust.id().as_ref()).unwrap(), $rust);
104+
)*
105+
};
106+
}
107+
108+
test_from_str! {
109+
"local/build-fail" => Crate::Local("build-fail".to_string()),
110+
"gh/org/user" => Crate::GitHub(GitHubRepo{org: "org".to_string(), name: "user".to_string(), sha: None}),
111+
"gh/org/user/sha" => Crate::GitHub(GitHubRepo{org: "org".to_string(), name: "user".to_string(), sha: Some("sha".to_string())}),
112+
"reg/name/version" => Crate::Registry(RegistryCrate{name: "name".to_string(), version: "version".to_string()}),
69113
}
70114
}
71115
}

src/crates/sources/github.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl List for GitHubList {
5555
list.push(Crate::GitHub(GitHubRepo {
5656
org: org.to_string(),
5757
name: name.to_string(),
58+
sha: None,
5859
}));
5960
} else {
6061
warn!("skipping malformed repo name: {}", line.name);
@@ -69,6 +70,7 @@ impl List for GitHubList {
6970
pub struct GitHubRepo {
7071
pub org: String,
7172
pub name: String,
73+
pub sha: Option<String>,
7274
}
7375

7476
impl GitHubRepo {
@@ -80,6 +82,7 @@ impl GitHubRepo {
8082
GitHubRepo {
8183
org: DUMMY_ORG.to_string(),
8284
name: DUMMY_NAME.to_string(),
85+
sha: None,
8386
}
8487
}
8588
}
@@ -88,17 +91,49 @@ impl FromStr for GitHubRepo {
8891
type Err = ::failure::Error;
8992

9093
fn from_str(input: &str) -> Fallible<Self> {
91-
let mut components = input.split('/').collect::<Vec<_>>();
92-
let name = components.pop();
94+
let mut components = input
95+
.trim_start_matches("https://github.com/")
96+
.split('/')
97+
.rev()
98+
.collect::<Vec<_>>();
9399
let org = components.pop();
100+
let name = components.pop();
101+
let sha = components.pop();
94102

95103
if let (Some(org), Some(name)) = (org, name) {
96104
Ok(GitHubRepo {
97105
org: org.to_string(),
98106
name: name.to_string(),
107+
sha: sha.map(|s| s.to_string()),
99108
})
100109
} else {
101110
bail!("malformed repo url: {}", input);
102111
}
103112
}
104113
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::GitHubRepo;
118+
use std::str::FromStr;
119+
120+
#[test]
121+
fn test_from_str() {
122+
assert_eq!(
123+
GitHubRepo::from_str("https://github.com/dummy_org/dummy/dummy_sha").unwrap(),
124+
GitHubRepo {
125+
org: "dummy_org".to_string(),
126+
name: "dummy".to_string(),
127+
sha: Some("dummy_sha".to_string())
128+
}
129+
);
130+
assert_eq!(
131+
GitHubRepo::from_str("https://github.com/dummy_org/dummy").unwrap(),
132+
GitHubRepo {
133+
org: "dummy_org".to_string(),
134+
name: "dummy".to_string(),
135+
sha: None
136+
}
137+
);
138+
}
139+
}

src/db/migrations.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,56 @@ fn migrations() -> Vec<(&'static str, MigrationKind)> {
313313
),
314314
));
315315

316+
migrations.push((
317+
"delete_sha_table",
318+
MigrationKind::SQL(
319+
"
320+
DROP TABLE shas;
321+
",
322+
),
323+
));
324+
325+
migrations.push((
326+
"stringify_crate_names",
327+
MigrationKind::Code(Box::new(|t| {
328+
use crate::crates::Crate;
329+
330+
let fn_name = format!(
331+
"crater_migration__{}",
332+
rand::thread_rng()
333+
.sample_iter(&Alphanumeric)
334+
.take(10)
335+
.collect::<String>()
336+
);
337+
t.create_scalar_function(&fn_name, 1, true, |ctx| {
338+
let legacy = ctx.get::<String>(0)?;
339+
340+
if let Ok(parsed) = serde_json::from_str::<Crate>(&legacy) {
341+
Ok(parsed.id())
342+
} else {
343+
Ok(legacy)
344+
}
345+
})?;
346+
347+
t.execute("PRAGMA foreign_keys = OFF;", no_args())?;
348+
t.execute(
349+
&format!("UPDATE experiment_crates SET crate = {}(crate);", fn_name),
350+
no_args(),
351+
)?;
352+
t.execute(
353+
&format!("UPDATE results SET crate = {}(crate);", fn_name),
354+
no_args(),
355+
)?;
356+
t.execute(
357+
&format!("UPDATE crates SET crate = {}(crate);", fn_name),
358+
no_args(),
359+
)?;
360+
t.execute("PRAGMA foreign_keys = ON;", no_args())?;
361+
362+
Ok(())
363+
})),
364+
));
365+
316366
migrations
317367
}
318368

0 commit comments

Comments
 (0)