std::shared_ptr readdirectory_cache::lookup()

in turbonfs/src/rpc_readdir.cpp [487:558]


std::shared_ptr<struct directory_entry> readdirectory_cache::lookup(
        cookie3 cookie,
        const char *filename_hint,
        bool acquire_lock) const
{
    AZLogDebug("[{}] lookup(cookie: {}, filename_hint: {})",
               dir_inode->ino, cookie, filename_hint ? filename_hint : "");

    // Either cookie or filename_hint (not both) must be passed.
    assert((cookie == 0) == (filename_hint != nullptr));

    /*
     * If acquire_lock is true, get shared lock on the map for looking up the
     * entry in the map. We use a dummy_lock for minimal code changes in the
     * no-lock case.
     * If you call it with acquire_lock=false make sure readdircache_lock_2
     * is held in shared or exclusive mode.
     */
    std::shared_mutex dummy_lock;
    std::shared_lock<std::shared_mutex> lock(
            acquire_lock ? readdircache_lock_2 : dummy_lock);

    if (filename_hint) {
        cookie = filename_to_cookie(filename_hint);
        if (cookie == 0) {
            AZLogDebug("[{}] filename_hint: {}, not found",
                       dir_inode->ino, filename_hint);
            return nullptr;
        }
        AZLogDebug("[{}] filename_hint: {}, found with cookie: {}",
                   dir_inode->ino, filename_hint, cookie);
    }

    const auto it = dir_entries.find(cookie);

    const std::shared_ptr<struct directory_entry>& dirent =
        (it != dir_entries.end()) ? it->second : nullptr;

    if (!dirent) {
        AZLogDebug("[{}] cookie: {}, not found",
                   dir_inode->ino, cookie);
    } else {
        AZLogDebug("[{}] cookie: {}, found, ino: {}",
                   dir_inode->ino, cookie,
                   dirent->nfs_inode ? dirent->nfs_inode->get_fuse_ino() : -1);
    }

    /*
     * If filename_hint was passed it MUST match the name in the dirent.
     */
    assert(!dirent || !filename_hint ||
           (::strcmp(dirent->name, filename_hint) == 0));

    if (dirent && dirent->nfs_inode) {
        /*
         * When a directory_entry is added to to readdirectory_cache we
         * hold a ref on the inode, so while it's in the dir_entries map,
         * dircachecnt must be non-zero.
         */
        assert(dirent->nfs_inode->dircachecnt > 0);

        /*
         * Grab a ref on behalf of the caller so that the inode doesn't
         * get freed while the directory_entry is referring to it.
         * Once they are done using this directory_entry, they must drop
         * this ref, mostly done in send_readdir_or_readdirplus_response().
         */
        dirent->nfs_inode->dircachecnt++;
    }

    return dirent;
}