readdir в AWS EFS не возвращает все файлы в каталоге

После записи большого количества файлов в ряд папок на EFS (10k или около того). Readdir прекращает возвращать все файлы в каждом каталоге.

У меня есть приложение C ++, которое в одной части своего процесса генерирует много файлов, и каждому файлу дается символическая ссылка. После этого мне нужно получить список файлов в папке, а затем выбрать подмножество для переименования. Когда я запускаю функцию, которая получает список файлов, она не возвращает все файлы, которые на самом деле там. Этот код отлично работает на моей локальной машине, но на сервере AWS с подключенным диском EFS через некоторое время он перестает работать.

Чтобы устранить эту проблему, я сделал так, чтобы мой код записывал только один файл за раз. Я также настроил свой код для использования getFiles (), чтобы подсчитывать, сколько файлов в папке после записи каждого пакета файлов (около 17 файлов). Когда количество файлов достигает ~ 950 файлов, getFiles () начинает перечислять ~ 910 файлов и больше не увеличивается. Когда он записывает файлы, файлы различаются, но довольно малы (2 байта — 300 КБ) и записывают около 200 файлов в секунду. Каждый файл также имеет символическую ссылку, созданную для него.

При чтении и записи файлов я использую posix open (), write (), read () и close (). Я подтвердил, что фактически закрываю все файлы после чтения или записи.

Я пытаюсь выяснить:
1. Почему не работает readdir? Или почему он не перечисляет все файлы?
2. Чем отличается EFS от проблем, которые могут вызывать проблемы?

Это функции, которые я использую для получения списка файлов в папке:

DIR * FileUtil::getDirStream(std::string path) {

bool success = false;

if (!folderExists(path)){
return NULL;
}

DIR * dir = opendir(path.c_str());
success = dir != NULL;

int count = 0;
while(!success){

int fileRetryDelay = BlazingConfig::getInstance()->getFileRetryDelay();
const int sleep_milliseconds = (count+1)*fileRetryDelay;
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_milliseconds));

std::cout<<"Was unable to get Dir stream for "<<path<<std::endl;
dir = opendir(path.c_str());
success = dir != NULL;

count++;
if(count > 6){
break;
}
}

if(success == -1){
std::cout<<"Can't get Dir stream for "<<path<<". Error was: "<<errno<<std::endl;
}
return dir;
}

int FileUtil::getDirEntry(DIR * dirp, struct dirent * & prevDirEntry, struct dirent * & dirEntry){

bool success = false;

if (dirp == NULL){
return -1;
}

int returnCode = readdir_r(dirp, prevDirEntry, &dirEntry);
success = (dirEntry == NULL && returnCode == 0) || dirEntry != NULL;

int count = 0;
while(!success){

int fileRetryDelay = BlazingConfig::getInstance()->getFileRetryDelay();
const int sleep_milliseconds = (count+1)*fileRetryDelay;
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_milliseconds));

std::cout<<"Was unable to get dirent with readdir"<<std::endl;

returnCode = readdir_r(dirp, prevDirEntry, &dirEntry);
success = (dirEntry == NULL && returnCode == 0) || dirEntry != NULL;

count++;
if(count > 6){
break;
}
}

if(success == -1){
std::cout<<"Can't get dirent with readdir. Error was: "<<errno<<std::endl;
}
return returnCode;
}

std::vector<std::string> FileUtil::getFiles(std::string baseFolder){
DIR *dir = getDirStream(baseFolder);
std::vector <std::string> subFolders;
if (dir != NULL) {
struct dirent *prevDirEntry = NULL;
struct dirent *dirEntry = NULL;
int len_entry = offsetof(struct dirent, d_name) + fpathconf(dirfd(dir), _PC_NAME_MAX) + 1;
prevDirEntry = (struct dirent *)malloc(len_entry);

int returnCode = getDirEntry(dir, prevDirEntry, dirEntry);

while (dirEntry != NULL) {
if( dirEntry->d_type == DT_REG || dirEntry->d_type == DT_LNK){
std::string name(dirEntry->d_name);
subFolders.push_back(name);
}
returnCode = getDirEntry(dir, prevDirEntry, dirEntry);
}

free(prevDirEntry);
closedir (dir);
} else {
std::cout<<"Could not open directory err num is"<<errno<<std::endl;
/* could not open directory */
perror ("");

}

return subFolders;
}

Функции были написаны таким образом, чтобы попытаться быть максимально устойчивыми, так как может быть много потоков, выполняющих файловые операции, я хотел иметь возможность повторять код в случае любых сбоев. К сожалению, когда getFiles () возвращает неправильный результат, это не дает мне никаких признаков сбоя.

Примечание: когда я использую readdir, а не readdir_r, у меня остается та же проблема.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …