Необычное поведение при удалении каталогов на SSD-диске
Каталог c:\test содержит около 50 файлов, без подкаталогов.
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
IO.Directory.CreateDirectory("C:\test")
Диск C - это твердотельный накопитель Intel X25-M80, ОС - 64-битная Windows 7 с поддержкой TRIM, Visual Studio 2008 с целевой платформой 3.5. Когда вышеуказанный код выполняется, CreateDirectory прерывает выполнение кода без (видимого) исключения. После большой головной боли я обнаружил, что удаление еще не выполнено к тому времени, когда выполнение кода попадает в CreateDirectory. Если я изменю свой код следующим образом:
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
Threading.Thread.Sleep(2000)
IO.Directory.CreateDirectory("C:\test")
тогда все работает как положено.
Мои вопросы помимо очевидного WTF здесь:
- не должен IO.Directory.Delete быть вызовом функции блокировки, независимо от того, что диск
- SSD "обманывает" при удалении из-за включенной поддержки TRIM?
6 ответов
У меня были проблемы с этим раньше, но это не относится к твердотельным накопителям. Вам было бы намного лучше сделать ход, затем удалить:
if(Directory.Exists(dirpath))
{
string temppath = dirpath + ".deleted";
Directory.Move(dirpath, temppath);
Directory.Delete(temppath, true);
}
Directory.Create(dirpath);
Другой способ справиться с этим - выполнить цикл до завершения:
if(Directory.Exists(dirpath))
{
Directory.Delete(dirpath, true);
int limit = 100;
while(Directory.Exists(dirpath) && limit-- > 0)
Thread.Sleep(0);
}
Directory.Create(dirpath);
После изучения System.IO.Directory с рефлектором, похоже, что.Delete является просто оболочкой для вызовов Win API FindFirstFile, FindNextFile и RemoveDirectory. Нет ничего поточного или асинхронного в вызове.Net этих вызовов API или в самой реализации API.
Теперь, предположив, что это каким-то образом проблема TRIM, вы можете отключить TRIM, открыв командную строку с повышенными привилегиями и используя fsutil:
fsutil behavior set disabledeletenotify 1
Для включения выполните ту же команду с 0 в качестве параметра.
Для запроса используйте запрос в качестве аргумента команды:
fsutil behavior query disabledeletenotify
Да, это не имеет никакого отношения к SSD-накопителю. У меня была такая же проблема, но только на клиентском ноутбуке. Я использую.NET 3.5. В моем случае в каталоге был один файл. Создается впечатление, что CreateDirectory сначала выполняется внутри, прежде чем удаление завершено.
Этот код хорошо работал три года на многих компьютерах. Клиент изменился на новый ноутбук, и код постоянно терпит неудачу для него. Я не могу воспроизвести сценарий на машинах разработки / тестирования с такой же конфигурацией.
У меня такая же проблема. Я закончил тем, что удалил только содержимое каталога @"C:\test"
и копирование новых файлов в каталог. Это была моя проблема:
Использование Directory.Delete() и Directory.CreateDirectory() для перезаписи папки
Я подозреваю, что вы обнаружили состояние гонки в NTFS, которое ранее не отображалось, поскольку не было накопителей, которые были достаточно быстры, чтобы поразить его. Я не думаю, что TRIM имеет какое-либо отношение к этому (хотя я оставляю за собой право ошибаться!)
В любом случае, правильный способ справиться с этим - поместить код в цикл Retry:
int retries = 3;
while(true) {
try {
doTheOperation();
break;
} catch (Exception ex) {
retries--;
if (retries == 0) {
throw;
}
Thread.Sleep(100);
continue;
}
}
Если это действительно код приложения, обратите внимание, что вы действительно пытаетесь удалить каталог с именем "est"!
Выйдите из пути "c:\test" или используйте оператор @ @"c:\test".