static int readdir_multi_head_optimize()

in src/s3fs.cpp [2733:2857]


static int readdir_multi_head_optimize(const char* path, const S3ObjList& head, void* buf, fuse_fill_dir_t filler)
{
    S3fsMultiCurl curlmulti(S3fsCurl::GetMaxMultiRequest());
    s3obj_list_t  headlist;
    s3obj_list_t  fillerlist;
    int           result = 0;
    s3obj_list_t  reheadlist;

    S3FS_PRN_INFO1("[path=%s][list=%zu]", path, headlist.size());

    // Make base path list.
    head.GetNameList(headlist, true, false);  // get name with "/".

    // Initialize S3fsMultiCurl
    curlmulti.SetSuccessCallback(multi_head_callback);
    curlmulti.SetRetryCallback(multi_head_retry_callback);

    s3obj_list_t::iterator iter;

    fillerlist.clear();
    // Make single head request(with max).
    for(iter = headlist.begin(); headlist.end() != iter; iter = headlist.erase(iter)){
        std::string disppath = path + (*iter);
        std::string etag     = head.GetETag((*iter).c_str());

        std::string fillpath = disppath;
        if('/' == *disppath.rbegin()){
            fillpath.erase(fillpath.length() -1);
        }
        fillerlist.push_back(fillpath);

        if(StatCache::getStatCacheData()->HasStat(disppath, etag.c_str())){
            continue;
        }

        //dir
        bool isDir = head.IsDir((*iter).c_str());
        if (isDir) {
            reheadlist.push_back(*iter);
            S3FS_PRN_DBG("reheadlist dir [path=%s]", (*iter).c_str());
            continue;
        }

        //use headrequest to get extended info
        std::string strsize = head.GetSize((*iter).c_str());
        off_t size = get_size(strsize.c_str());
        if (is_check_meta(size, readdir_check_size)) {
            reheadlist.push_back(*iter);
            S3FS_PRN_DBG("reheadlist size limit [path=%s, size=%s]", (*iter).c_str(), strsize.c_str());
            continue;
        }

        // conver meta to header_t
        std::string lastmodified = head.GetLastModified((*iter).c_str());
        headers_t headers;
        headers["Content-Length"] = strsize;
        headers["Last-Modified"] = utc_to_gmt(lastmodified.c_str());
        if(!StatCache::getStatCacheData()->AddStat(disppath, headers, /*forcedir*/false, /*no_truncate*/false, true)){
            S3FS_PRN_ERR("failed adding stat cache [path=%s]", disppath.c_str());
        }
    }

    //check from header meta
    for(iter = reheadlist.begin(); reheadlist.end() != iter; ++iter){
        std::string disppath = path + (*iter);
        S3fsCurl* s3fscurl = new S3fsCurl();
        if(!s3fscurl->PreHeadRequest(disppath, (*iter), disppath)){  // target path = cache key path.(ex "dir/")
            S3FS_PRN_WARN("Could not make curl object for head request(%s).", disppath.c_str());
            delete s3fscurl;
            continue;
        }

        if(!curlmulti.SetS3fsCurlObject(s3fscurl)){
            S3FS_PRN_WARN("Could not make curl object into multi curl(%s).", disppath.c_str());
            delete s3fscurl;
            continue;
        }
    }

    // Multi request
    if(0 != (result = curlmulti.Request())){
        if(-EIO == result){
            S3FS_PRN_WARN("error occurred in multi request(errno=%d), but continue...", result);
            result = 0;
        }else{
            S3FS_PRN_ERR("error occurred in multi request(errno=%d).", result);
            return result;
        }
    }

    // if the dir exists in reheadlist, but is not in stat cache,
    // it is just a common prefix, need add to stat cache.
    headers_t emptyheaders;
    for(iter = reheadlist.begin(); reheadlist.end() != iter; iter = reheadlist.erase(iter)){
        std::string disppath = path + (*iter);
        bool isDir = head.IsDir((*iter).c_str());
        if (isDir) {
            if (!StatCache::getStatCacheData()->HasStat(disppath)) {
                if(!StatCache::getStatCacheData()->AddStat(disppath, emptyheaders, isDir)){
                    S3FS_PRN_ERR("failed adding stat cache [path=%s]", disppath.c_str());
                }
            }
        }
    }

    // populate fuse buffer
    // here is best position, because a case is cache size < files in directory
    //
    for(iter = fillerlist.begin(); fillerlist.end() != iter; ++iter){
        struct stat st;
        bool in_cache = StatCache::getStatCacheData()->GetStat((*iter), &st);
        std::string bpath = mybasename((*iter));
        if(use_wtf8){
            bpath = s3fs_wtf8_decode(bpath);
        }
        if(in_cache){
            filler(buf, bpath.c_str(), &st, 0);
        }else{
            S3FS_PRN_INFO2("Could not find %s file in stat cache.", (*iter).c_str());
            filler(buf, bpath.c_str(), 0, 0);
        }
    }

    return result;
}