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;
}