in src/fs.rs [166:300]
fn load_dir(&self, prefix: Option<String>, parent: Option<Inode>) -> Inode {
let bucket_clone = self.gcs_bucket.clone();
let prefix_clone = prefix.clone();
let prefix_for_load: String = match prefix {
Some(prefix_str) => prefix_str,
None => String::from(""),
};
// As above (this is too noisy for debugging regular FS operation).
//debug!(" GCSFS. DIR {}", prefix_for_load);
// Always use / as delim.
let (single_level_objs, subdirs) = self
.tokio_rt
.block_on(async {
super::gcs::list_objects(
&self.gcs_client,
bucket_clone.as_ref(),
prefix_clone.as_deref(),
Some("/"),
)
.await
})
.unwrap();
let dir_inode = self.get_inode();
let dir_time: SystemTime = UNIX_EPOCH + Duration::new(1534812086, 0); // 2018-08-20 15:41 Pacific
let dir_attr: FileAttr = FileAttr {
ino: dir_inode,
size: 0,
blocks: 0,
atime: dir_time,
mtime: dir_time,
ctime: dir_time,
crtime: dir_time,
kind: FileType::Directory,
perm: 0o755,
nlink: (single_level_objs.len() + 2) as u32,
uid: 501,
gid: 20,
rdev: 0,
flags: 0,
blksize: HARDCODED_BLOCKSIZE,
};
self.inode_to_attr
.write()
.unwrap()
.insert(dir_inode, dir_attr);
let parent_inode = match parent {
Some(parent_val) => parent_val,
None => dir_inode,
};
let mut dir_entries: Vec<(String, Inode)> = vec![
(String::from("."), dir_inode), /* self link */
(String::from(".."), parent_inode),
];
// GCS returns paths relative to the root of the bucket for
// obj.name. Strip off the prefix to get the "filename".
let base_dir_index = prefix_for_load.len();
// Load the subdirectories in parallel, gathering up their results in order.
let subdir_len = subdirs.len();
let inodes: Arc<RwLock<Vec<Inode>>> = Arc::new(RwLock::new(Vec::with_capacity(subdir_len)));
// Pre-fill the array with 0s, so we can write into each slot blindly later.
inodes
.write()
.unwrap()
.resize_with(subdir_len, Default::default);
rayon::scope(|s| {
// NOTE(boulos): We have to do this so that the move
// closure below doesn't capture the real self / we
// indicate that its lifetime matches that of this Rayon
// scope.
let shadow_self = &self;
// Loop over all the subdirs, recursively loading them.
for (i, dir) in subdirs.iter().enumerate() {
let inodes_clone = Arc::clone(&inodes);
s.spawn(move |_| {
let inode = shadow_self.load_dir(Some(dir.to_string()), Some(dir_inode));
let mut write_context = inodes_clone.write().unwrap();
if let Some(elem) = write_context.get_mut(i) {
*elem = inode;
} else {
println!(
"ERROR: Tried to write inode '{}' to index {} \
for directory {} (subdirs has len {})",
inode, i, dir, subdir_len
);
}
});
}
});
for (i, dir) in subdirs.iter().enumerate() {
// To insert the "directory name", we get the basedir and
// strip the trailing slash.
let last_slash = dir.len() - 1;
let dir_str = dir[base_dir_index..last_slash].to_string();
let read_context = inodes.read().unwrap();
dir_entries.push((dir_str, read_context[i]));
}
// Loop over all the direct objects, adding them to our maps
for obj in single_level_objs {
// Extract just the portion that is the "file name".
let file_str = obj.name[base_dir_index..].to_string();
let full_path = format!("{}{}", prefix_for_load, file_str);
let inode = self.load_file(full_path, obj);
dir_entries.push((file_str, inode));
}
//debug!(" Created dir_entries: {:#?}", dir_entries);
self.directory_map.write().unwrap().insert(
dir_inode,
PsuedoDir {
name: prefix_for_load,
entries: dir_entries,
},
);
dir_inode
}