В нашем приложении нам приходится часто записывать большие файлы (от 100 МБ до нескольких ГБ) на удаленных машинах (в том же сегменте локальной сети).Это узкое место нашего приложения.Удаленные машины могут быть как Windows, так и Linux, использующими SMB.
Мы обнаружили, что создание файлов сначала локально, а затем копирование их с помощью функции Windows API CopyFile НАМНОГО быстрее, чем при использовании Создать файл напрямую с UNC-путем (или буквой диска) для удаленного компьютера.Но все же мы должны сделать 2 записи, которые кажутся далеко не оптимальными.
Вдохновленный первыми комментариями по этому вопросу, я реализовал использование FILE_FLAG_OVERLAPPED для CreateFile, как обсуждалось здесь и здесь:
HANDLE hToken;
auto openResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if (!openResult)
{
gConsoleAndLog << "OpenProcessToken failed with err " << GetLastError() << std::endl;
}
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 3;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
if(! LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &tp.Privileges[0].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_MANAGE_VOLUME_NAME failed with err " << GetLastError() << std::endl;
if (! LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &tp.Privileges[1].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_INCREASE_QUOTA_NAME failed with err " << GetLastError() << std::endl;
if (! LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tp.Privileges[2].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_ASSIGNPRIMARYTOKEN_NAME failed with err " << GetLastError() << std::endl;
auto adjustResult = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
if (!adjustResult || GetLastError() != ERROR_SUCCESS)
{
gConsoleAndLog << "AdjustTokenPrivileges failed with err " << GetLastError() << std::endl;
}
else gConsoleAndLog << "AdjustTokenPrivileges SUCCESS" << std::endl;
В отличие от второго поста, я не могу установить привилегию "SE_ASSIGNPRIMARYTOKEN_NAME" даже при запуске от имени администратора.Я не знаю, если это имеет значение.
После открытия файла с FILE_FLAG_NO_BUFFERING |FILE_FLAG_OVERLAPPED, предварительно рассчитанный размер выделен:
auto setFileErr = SetFilePointerEx(hFile, endPosition, NULL, FILE_BEGIN);
if (setFileErr == INVALID_SET_FILE_POINTER)
{
CPrintWithOSError(NULL, 0, "SetFilePointerEx FAILED");
return 1;
}
if (!SetEndOfFile(hFile))
{
CPrintWithOSError(NULL, 0, "SetEndOfFile FAILED");
return 1;
}
if (!SetFileValidData(hFile, endPosition.QuadPart))
{
CPrintWithOSError(NULL, 0, "SetFileValidData FAILED");
return 1;
}
Это работает для локальных дисков, но SetFileValidData не работает на удаленных дисках.
Вызов завершается ошибкой с ошибкой Windows
1314 a required privilege is not held by the client
- Как это можно исправить?
- Какие есть другие способы сделать это?
- Есть ли способ увеличить буферизацию файлов для добавления записей с помощью WinAPI?