Skip to content

Commit 9df9b38

Browse files
committed
Merge remote-tracking branch 'apache/master' into gauge
2 parents e4410e0 + 48ad975 commit 9df9b38

5 files changed

Lines changed: 55 additions & 68 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Here are some of the projects known to use DataFusion:
6767
- [ROAPI](https://github.com/roapi/roapi)
6868
- [Tensorbase](https://github.com/tensorbase/tensorbase)
6969
- [Squirtle](https://github.com/DSLAM-UMD/Squirtle)
70+
- [VegaFusion](https://vegafusion.io/) Server-side acceleration for the [Vega](https://vega.github.io/) visualization grammar
7071

7172
(if you know of another project, please submit a PR to add a link!)
7273

ballista/rust/core/src/execution_plans/shuffle_writer.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,10 @@ impl ShuffleWriterExec {
265265
std::fs::create_dir_all(&path)?;
266266

267267
path.push(format!("data-{}.arrow", input_partition));
268-
let path = path.to_str().unwrap();
269-
info!("Writing results to {}", path);
268+
info!("Writing results to {:?}", path);
270269

271270
let mut writer =
272-
IPCWriter::new(path, stream.schema().as_ref())?;
271+
IPCWriter::new(&path, stream.schema().as_ref())?;
273272

274273
writer.write(&output_batch)?;
275274
writers[output_partition] = Some(writer);
@@ -287,7 +286,7 @@ impl ShuffleWriterExec {
287286
Some(w) => {
288287
w.finish()?;
289288
info!(
290-
"Finished writing shuffle partition {} at {}. Batches: {}. Rows: {}. Bytes: {}.",
289+
"Finished writing shuffle partition {} at {:?}. Batches: {}. Rows: {}. Bytes: {}.",
291290
i,
292291
w.path(),
293292
w.num_batches,
@@ -297,7 +296,7 @@ impl ShuffleWriterExec {
297296

298297
part_locs.push(ShuffleWritePartition {
299298
partition_id: i as u64,
300-
path: w.path().to_owned(),
299+
path: w.path().to_string_lossy().to_string(),
301300
num_batches: w.num_batches,
302301
num_rows: w.num_rows,
303302
num_bytes: w.num_bytes,

datafusion/src/execution/disk_manager.rs

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,10 @@
2020
2121
use crate::error::{DataFusionError, Result};
2222
use log::{debug, info};
23-
use rand::distributions::Alphanumeric;
2423
use rand::{thread_rng, Rng};
25-
use std::collections::hash_map::DefaultHasher;
26-
use std::fs::File;
27-
use std::hash::{Hash, Hasher};
28-
use std::path::{Path, PathBuf};
24+
use std::path::PathBuf;
2925
use std::sync::Arc;
30-
use tempfile::{Builder, TempDir};
26+
use tempfile::{Builder, NamedTempFile, TempDir};
3127

3228
/// Configuration for temporary disk access
3329
#[derive(Debug, Clone)]
@@ -101,8 +97,8 @@ impl DiskManager {
10197
}
10298
}
10399

104-
/// Create a file in conf dirs in randomized manner and return the file path
105-
pub fn create_tmp_file(&self) -> Result<String> {
100+
/// Return a temporary file from a randomized choice in the configured locations
101+
pub fn create_tmp_file(&self) -> Result<NamedTempFile> {
106102
create_tmp_file(&self.local_dirs)
107103
}
108104
}
@@ -120,34 +116,15 @@ fn create_local_dirs(local_dirs: Vec<PathBuf>) -> Result<Vec<TempDir>> {
120116
.collect()
121117
}
122118

123-
fn get_file(file_name: &str, local_dirs: &[TempDir]) -> String {
124-
let mut hasher = DefaultHasher::new();
125-
file_name.hash(&mut hasher);
126-
let hash = hasher.finish();
127-
let dir = &local_dirs[hash.rem_euclid(local_dirs.len() as u64) as usize];
128-
let mut path = PathBuf::new();
129-
path.push(dir);
130-
path.push(file_name);
131-
path.to_str().unwrap().to_string()
132-
}
119+
fn create_tmp_file(local_dirs: &[TempDir]) -> Result<NamedTempFile> {
120+
let dir_index = thread_rng().gen_range(0..local_dirs.len());
121+
let dir = local_dirs.get(dir_index).ok_or_else(|| {
122+
DataFusionError::Internal("No directories available to DiskManager".into())
123+
})?;
133124

134-
fn create_tmp_file(local_dirs: &[TempDir]) -> Result<String> {
135-
let name = rand_name();
136-
let mut path = get_file(&*name, local_dirs);
137-
while Path::new(path.as_str()).exists() {
138-
path = get_file(&rand_name(), local_dirs);
139-
}
140-
File::create(&path)?;
141-
Ok(path)
142-
}
143-
144-
/// Return a random string suitable for use as a database name
145-
fn rand_name() -> String {
146-
thread_rng()
147-
.sample_iter(&Alphanumeric)
148-
.take(10)
149-
.map(char::from)
150-
.collect()
125+
Builder::new()
126+
.tempfile_in(dir)
127+
.map_err(DataFusionError::IoError)
151128
}
152129

153130
#[cfg(test)]
@@ -161,19 +138,28 @@ mod tests {
161138
let local_dir1 = TempDir::new()?;
162139
let local_dir2 = TempDir::new()?;
163140
let local_dir3 = TempDir::new()?;
164-
let config = DiskManagerConfig::new_specified(vec![
165-
local_dir1.path().into(),
166-
local_dir2.path().into(),
167-
local_dir3.path().into(),
168-
]);
141+
let local_dirs = vec![local_dir1.path(), local_dir2.path(), local_dir3.path()];
142+
let config = DiskManagerConfig::new_specified(
143+
local_dirs.iter().map(|p| p.into()).collect(),
144+
);
169145

170146
let dm = DiskManager::try_new(config)?;
171147
let actual = dm.create_tmp_file()?;
172-
let name = actual.rsplit_once(std::path::MAIN_SEPARATOR).unwrap().1;
173148

174-
let expected = get_file(name, &dm.local_dirs);
175-
// file should be located in dir by it's name hash
176-
assert_eq!(actual, expected);
149+
// the file should be in one of the specified local directories
150+
let found = local_dirs.iter().any(|p| {
151+
actual
152+
.path()
153+
.ancestors()
154+
.any(|candidate_path| *p == candidate_path)
155+
});
156+
157+
assert!(
158+
found,
159+
"Can't find {:?} in specified local dirs: {:?}",
160+
actual, local_dirs
161+
);
162+
177163
Ok(())
178164
}
179165
}

datafusion/src/physical_plan/common.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use futures::{Future, SinkExt, Stream, StreamExt, TryStreamExt};
3333
use pin_project_lite::pin_project;
3434
use std::fs;
3535
use std::fs::{metadata, File};
36+
use std::path::{Path, PathBuf};
3637
use std::sync::Arc;
3738
use std::task::{Context, Poll};
3839
use tokio::task::JoinHandle;
@@ -387,7 +388,7 @@ mod tests {
387388
/// Write in Arrow IPC format.
388389
pub struct IPCWriter {
389390
/// path
390-
pub path: String,
391+
pub path: PathBuf,
391392
/// Inner writer
392393
pub writer: FileWriter<File>,
393394
/// bathes written
@@ -400,18 +401,18 @@ pub struct IPCWriter {
400401

401402
impl IPCWriter {
402403
/// Create new writer
403-
pub fn new(path: &str, schema: &Schema) -> Result<Self> {
404+
pub fn new(path: &Path, schema: &Schema) -> Result<Self> {
404405
let file = File::create(path).map_err(|e| {
405406
DataFusionError::Execution(format!(
406-
"Failed to create partition file at {}: {:?}",
407+
"Failed to create partition file at {:?}: {:?}",
407408
path, e
408409
))
409410
})?;
410411
Ok(Self {
411412
num_batches: 0,
412413
num_rows: 0,
413414
num_bytes: 0,
414-
path: path.to_owned(),
415+
path: path.into(),
415416
writer: FileWriter::try_new(file, schema)?,
416417
})
417418
}
@@ -432,7 +433,7 @@ impl IPCWriter {
432433
}
433434

434435
/// Path write to
435-
pub fn path(&self) -> &str {
436+
pub fn path(&self) -> &Path {
436437
&self.path
437438
}
438439
}

datafusion/src/physical_plan/sorts/sort.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ use std::fmt;
5050
use std::fmt::{Debug, Formatter};
5151
use std::fs::File;
5252
use std::io::BufReader;
53+
use std::path::{Path, PathBuf};
5354
use std::sync::Arc;
5455
use tokio::sync::mpsc::{Receiver, Sender};
56+
use tempfile::NamedTempFile;
5557
use tokio::task;
5658

5759
/// Sort arbitrary size of data to get a total order (may spill several times during sorting based on free memory available).
@@ -67,7 +69,7 @@ struct ExternalSorter {
6769
id: MemoryConsumerId,
6870
schema: SchemaRef,
6971
in_mem_batches: Mutex<Vec<RecordBatch>>,
70-
spills: Mutex<Vec<String>>,
72+
spills: Mutex<Vec<NamedTempFile>>,
7173
/// Sort expressions
7274
expr: Vec<PhysicalSortExpr>,
7375
runtime: Arc<RuntimeEnv>,
@@ -222,20 +224,19 @@ impl MemoryConsumer for ExternalSorter {
222224

223225
let baseline_metrics = self.metrics.new_intermediate_baseline(partition);
224226

225-
let path = self.runtime.disk_manager.create_tmp_file()?;
227+
let spillfile = self.runtime.disk_manager.create_tmp_file()?;
226228
let stream = in_mem_partial_sort(
227229
&mut *in_mem_batches,
228230
self.schema.clone(),
229231
&*self.expr,
230232
baseline_metrics,
231233
);
232234

233-
spill_partial_sorted_stream(&mut stream?, path.clone(), self.schema.clone())
234-
.await?;
235+
spill_partial_sorted_stream(&mut stream?, spillfile.path(), self.schema.clone()).await?;
235236
let mut spills = self.spills.lock().await;
236237
let used = self.inner_metrics.mem_used().set(0);
237238
self.inner_metrics.record_spill(used);
238-
spills.push(path);
239+
spills.push(spillfile);
239240
Ok(used)
240241
}
241242

@@ -280,12 +281,12 @@ fn in_mem_partial_sort(
280281

281282
async fn spill_partial_sorted_stream(
282283
in_mem_stream: &mut SendableRecordBatchStream,
283-
path: String,
284+
path: &Path,
284285
schema: SchemaRef,
285286
) -> Result<()> {
286287
let (sender, receiver) = tokio::sync::mpsc::channel(2);
287-
let path_clone = path.clone();
288-
let handle = task::spawn_blocking(move || write_sorted(receiver, path_clone, schema));
288+
let path: PathBuf = path.into();
289+
let handle = task::spawn_blocking(move || write_sorted(receiver, path, schema));
289290
while let Some(item) = in_mem_stream.next().await {
290291
sender.send(item).await.ok();
291292
}
@@ -300,17 +301,16 @@ async fn spill_partial_sorted_stream(
300301
}
301302

302303
fn read_spill_as_stream(
303-
path: String,
304+
path: NamedTempFile,
304305
schema: SchemaRef,
305306
) -> Result<SendableRecordBatchStream> {
306307
let (sender, receiver): (
307308
Sender<ArrowResult<RecordBatch>>,
308309
Receiver<ArrowResult<RecordBatch>>,
309310
) = tokio::sync::mpsc::channel(2);
310-
let path_clone = path.clone();
311311
let join_handle = task::spawn_blocking(move || {
312-
if let Err(e) = read_spill(sender, path_clone) {
313-
error!("Failure while reading spill file: {}. Error: {}", path, e);
312+
if let Err(e) = read_spill(sender, path.path()) {
313+
error!("Failure while reading spill file: {:?}. Error: {}", path, e);
314314
}
315315
});
316316
Ok(RecordBatchReceiverStream::create(
@@ -322,7 +322,7 @@ fn read_spill_as_stream(
322322

323323
fn write_sorted(
324324
mut receiver: Receiver<ArrowResult<RecordBatch>>,
325-
path: String,
325+
path: PathBuf,
326326
schema: SchemaRef,
327327
) -> Result<()> {
328328
let mut writer = IPCWriter::new(path.as_ref(), schema.as_ref())?;
@@ -337,7 +337,7 @@ fn write_sorted(
337337
Ok(())
338338
}
339339

340-
fn read_spill(sender: Sender<ArrowResult<RecordBatch>>, path: String) -> Result<()> {
340+
fn read_spill(sender: Sender<ArrowResult<RecordBatch>>, path: &Path) -> Result<()> {
341341
let file = BufReader::new(File::open(&path)?);
342342
let reader = FileReader::try_new(file)?;
343343
for batch in reader {

0 commit comments

Comments
 (0)