fn load_dir()

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
    }