Skip to content

Commit f4b855b

Browse files
RUST-1473 Add GridFS Benchmarks (#772)
1 parent f626372 commit f4b855b

File tree

14 files changed

+516
-80
lines changed

14 files changed

+516
-80
lines changed

.evergreen/benchmarks.yml

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -275,62 +275,32 @@ post:
275275
- func: "cleanup"
276276

277277
tasks:
278-
- name: "benchmark-4.2-standalone"
279-
tags: ["4.2", "standalone"]
278+
- name: "benchmark-rapid-standalone"
279+
tags: ["rapid", "standalone"]
280280
commands:
281281
- func: "bootstrap mongo-orchestration"
282282
vars:
283-
MONGODB_VERSION: "4.2"
283+
MONGODB_VERSION: "rapid"
284284
TOPOLOGY: "server"
285285
- func: "run driver benchmarks"
286286
- func: "upload benchmark results"
287287

288-
- name: "benchmark-4.2-replica_set"
289-
tags: ["4.2", "replica_set"]
288+
- name: "benchmark-rapid-replica_set"
289+
tags: ["rapid", "replica_set"]
290290
commands:
291291
- func: "bootstrap mongo-orchestration"
292292
vars:
293-
MONGODB_VERSION: "4.2"
293+
MONGODB_VERSION: "rapid"
294294
TOPOLOGY: "replica_set"
295295
- func: "run driver benchmarks"
296296
- func: "upload benchmark results"
297297

298-
- name: "benchmark-4.2-sharded_cluster"
299-
tags: ["4.2", "sharded_cluster"]
298+
- name: "benchmark-rapid-sharded_cluster"
299+
tags: ["rapid", "sharded_cluster"]
300300
commands:
301301
- func: "bootstrap mongo-orchestration"
302302
vars:
303-
MONGODB_VERSION: "4.2"
304-
TOPOLOGY: "sharded_cluster"
305-
- func: "run driver benchmarks"
306-
- func: "upload benchmark results"
307-
308-
- name: "benchmark-5.0-standalone"
309-
tags: ["5.0", "standalone"]
310-
commands:
311-
- func: "bootstrap mongo-orchestration"
312-
vars:
313-
MONGODB_VERSION: "5.0"
314-
TOPOLOGY: "server"
315-
- func: "run driver benchmarks"
316-
- func: "upload benchmark results"
317-
318-
- name: "benchmark-5.0-replica_set"
319-
tags: ["5.0", "replica_set"]
320-
commands:
321-
- func: "bootstrap mongo-orchestration"
322-
vars:
323-
MONGODB_VERSION: "5.0"
324-
TOPOLOGY: "replica_set"
325-
- func: "run driver benchmarks"
326-
- func: "upload benchmark results"
327-
328-
- name: "benchmark-5.0-sharded_cluster"
329-
tags: ["5.0", "sharded_cluster"]
330-
commands:
331-
- func: "bootstrap mongo-orchestration"
332-
vars:
333-
MONGODB_VERSION: "5.0"
303+
MONGODB_VERSION: "rapid"
334304
TOPOLOGY: "sharded_cluster"
335305
- func: "run driver benchmarks"
336306
- func: "upload benchmark results"
@@ -350,14 +320,10 @@ axes:
350320
- id: "mongodb-version"
351321
display_name: MongoDB Version
352322
values:
353-
- id: "5.0"
354-
display_name: "5.0"
355-
variables:
356-
MONGODB_VERSION: "5.0"
357-
- id: "4.2"
358-
display_name: "4.2"
323+
- id: "rapid"
324+
display_name: "rapid"
359325
variables:
360-
MONGODB_VERSION: "4.2"
326+
MONGODB_VERSION: "rapid"
361327

362328
- id: "topology"
363329
display_name: Topology
@@ -434,8 +400,7 @@ buildvariants:
434400
async-runtime: "*"
435401
display_name: "${os} ${auth-and-tls} with ${async-runtime}"
436402
tasks:
437-
- ".5.0"
438-
- ".4.2"
403+
- ".rapid"
439404
-
440405
matrix_name: "bson benchmarks"
441406
matrix_spec:

benchmarks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ clap = "2.33.3"
2424
indicatif = "0.15.0"
2525
async-trait = "0.1.41"
2626
tokio = { version = "1.6", features = ["sync"] }
27+
tokio-util = "0.7"
2728
tokio-stream = { version = "0.1.6", features = ["io-util"], optional = true }
2829
# "unstable" feature is needed for `spawn_blocking`, which is only used in task setup
2930
async-std = { version = "1.9.0", optional = true, features = ["attributes", "unstable"] }

benchmarks/README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,31 @@ When running the benchmarks with the `--ids` flag, you can refer to each benchma
2020
benchmarks by separating each benchmark's id with a comma. For example `cargo run --release -- --ids 1,2,3,4` would run all
2121
the single-doc benchmarks. By default, all benchmarks are executed. The table below lists each benchmark's id.
2222

23-
| Benchmark | ID |
24-
|--------------------------------|----|
25-
| Run command | 1 |
26-
| Find one by ID | 2 |
27-
| Small doc insertOne | 3 |
28-
| Large doc insertOne | 4 |
29-
| Find many and empty the cursor | 5 |
30-
| Small doc bulk insert | 6 |
31-
| Large doc bulk insert | 7 |
32-
| LDJSON multi-file import | 8 |
33-
| LDJSON multi-file export | 9 |
34-
| BSON flat decode | 10 |
35-
| BSON flat encode | 11 |
36-
| BSON deeply nested decode | 12 |
37-
| BSON deeply nested encode | 13 |
38-
| BSON full document decode | 14 |
39-
| BSON full document encode | 15 |
40-
| All benchmarks | all|
23+
| Benchmark | ID |
24+
|----------------------------------------------- |----|
25+
| Run command | 1 |
26+
| Find one by ID | 2 |
27+
| Small doc insertOne | 3 |
28+
| Large doc insertOne | 4 |
29+
| Find many and empty the cursor | 5 |
30+
| Small doc bulk insert | 6 |
31+
| Large doc bulk insert | 7 |
32+
| LDJSON multi-file import | 8 |
33+
| LDJSON multi-file export | 9 |
34+
| BSON flat decode | 10 |
35+
| BSON flat encode | 11 |
36+
| BSON deeply nested decode | 12 |
37+
| BSON deeply nested encode | 13 |
38+
| BSON full document decode | 14 |
39+
| BSON full document encode | 15 |
40+
| Find many and empty the cursor (raw BSON) | 16 |
41+
| Find many and empty the cursor (serde structs) | 17 |
42+
| GridFS download | 18 |
43+
| GridFS upload | 19 |
44+
| GridFS multi-file download | 20 |
45+
| GridFS multi-file upload | 21 |
46+
| All benchmarks | all|
4147

4248
Note that in order to compare against the other drivers, an inMemory mongod instance should be used.
4349

44-
At this point, GridFS benchmarks are not implemented because it has not been implemented in the driver.
45-
4650
Also note that the parallel benchmarks are implemented to mirror the C++ driver's interpretation of the spec.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::path::PathBuf;
2+
3+
use anyhow::{Context, Result};
4+
use mongodb::{bson::Bson, gridfs::GridFsBucket, Client};
5+
6+
use crate::{
7+
bench::{drop_database, Benchmark, DATABASE_NAME},
8+
fs::open_async_read_compat,
9+
};
10+
11+
pub struct GridFsDownloadBenchmark {
12+
uri: String,
13+
bucket: GridFsBucket,
14+
file_id: Bson,
15+
}
16+
17+
pub struct Options {
18+
pub uri: String,
19+
pub path: PathBuf,
20+
}
21+
22+
#[async_trait::async_trait]
23+
impl Benchmark for GridFsDownloadBenchmark {
24+
type Options = Options;
25+
26+
async fn setup(options: Self::Options) -> Result<Self> {
27+
let client = Client::with_uri_str(&options.uri).await?;
28+
let db = client.database(&DATABASE_NAME);
29+
drop_database(&options.uri, &DATABASE_NAME)
30+
.await
31+
.context("drop database setup")?;
32+
33+
let bucket = db.gridfs_bucket(None);
34+
35+
let file = open_async_read_compat(&options.path).await?;
36+
let file_id = bucket
37+
.upload_from_futures_0_3_reader("gridfstest", file, None)
38+
.await
39+
.context("upload file")?;
40+
41+
Ok(Self {
42+
uri: options.uri,
43+
bucket,
44+
file_id: file_id.into(),
45+
})
46+
}
47+
48+
async fn do_task(&self) -> Result<()> {
49+
let mut buf = vec![];
50+
self.bucket
51+
.download_to_futures_0_3_writer(self.file_id.clone(), &mut buf)
52+
.await
53+
.context("download file")?;
54+
55+
Ok(())
56+
}
57+
58+
async fn teardown(&self) -> Result<()> {
59+
drop_database(&self.uri, &DATABASE_NAME)
60+
.await
61+
.context("drop database teardown")?;
62+
63+
Ok(())
64+
}
65+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use std::{
2+
fs::{create_dir, read_dir, remove_file},
3+
path::{Path, PathBuf},
4+
};
5+
6+
use anyhow::{Context, Result};
7+
use futures::AsyncWriteExt;
8+
use lazy_static::lazy_static;
9+
use mongodb::{bson::oid::ObjectId, gridfs::GridFsBucket, Client};
10+
11+
use crate::{
12+
bench::{drop_database, Benchmark, DATABASE_NAME},
13+
fs::{open_async_read_compat, open_async_write_compat},
14+
};
15+
16+
lazy_static! {
17+
static ref DOWNLOAD_PATH: PathBuf =
18+
Path::new(env!("CARGO_MANIFEST_DIR")).join("gridfs_multi_download");
19+
}
20+
21+
pub struct GridFsMultiDownloadBenchmark {
22+
uri: String,
23+
bucket: GridFsBucket,
24+
ids: Vec<ObjectId>,
25+
}
26+
27+
pub struct Options {
28+
pub uri: String,
29+
pub path: PathBuf,
30+
}
31+
32+
#[async_trait::async_trait]
33+
impl Benchmark for GridFsMultiDownloadBenchmark {
34+
type Options = Options;
35+
36+
async fn setup(options: Self::Options) -> Result<Self> {
37+
let client = Client::with_uri_str(&options.uri).await?;
38+
let db = client.database(&DATABASE_NAME);
39+
drop_database(&options.uri, &DATABASE_NAME)
40+
.await
41+
.context("drop database setup")?;
42+
43+
let bucket = db.gridfs_bucket(None);
44+
bucket.drop().await.context("drop bucket setup")?;
45+
46+
let mut ids = vec![];
47+
for entry in read_dir(options.path)? {
48+
let path = entry?.path();
49+
50+
let file = open_async_read_compat(&path).await?;
51+
let id = bucket
52+
.upload_from_futures_0_3_reader(path.display().to_string(), file, None)
53+
.await
54+
.context("upload file")?;
55+
ids.push(id);
56+
}
57+
58+
create_dir(DOWNLOAD_PATH.as_path())?;
59+
60+
Ok(Self {
61+
uri: options.uri,
62+
bucket,
63+
ids,
64+
})
65+
}
66+
67+
async fn before_task(&mut self) -> Result<()> {
68+
for id in &self.ids {
69+
let path = get_filename(id.clone());
70+
if Path::try_exists(&path)? {
71+
remove_file(path)?;
72+
}
73+
}
74+
75+
Ok(())
76+
}
77+
78+
async fn do_task(&self) -> Result<()> {
79+
let mut tasks = vec![];
80+
81+
for id in &self.ids {
82+
let bucket = self.bucket.clone();
83+
let id = id.clone();
84+
85+
tasks.push(crate::spawn(async move {
86+
let download_path = get_filename(id);
87+
let mut file = open_async_write_compat(&download_path)
88+
.await
89+
.context("open file")?;
90+
91+
bucket
92+
.download_to_futures_0_3_writer(id.into(), &mut file)
93+
.await
94+
.context("download file")?;
95+
96+
file.flush().await?;
97+
98+
let ok: anyhow::Result<()> = Ok(());
99+
ok
100+
}));
101+
}
102+
103+
for task in tasks {
104+
task.await?;
105+
}
106+
107+
Ok(())
108+
}
109+
110+
async fn teardown(&self) -> Result<()> {
111+
drop_database(&self.uri, &DATABASE_NAME)
112+
.await
113+
.context("drop database teardown")?;
114+
115+
Ok(())
116+
}
117+
}
118+
119+
fn get_filename(id: ObjectId) -> PathBuf {
120+
DOWNLOAD_PATH.join(format!("file{}.txt", id))
121+
}

0 commit comments

Comments
 (0)