Необычное поведение удаления каталогов на накопителе 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 - это SSD-накопитель 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?
Ответы
Ответ 1
У меня были проблемы с этим раньше, но это не относится к дискам SSD. Вам было бы намного лучше сделать ход, а затем удалить:
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);
Ответ 2
После изучения System.IO.Directory с рефлектором это выглядит как .Delete - это всего лишь оболочка вызовов FindFirstFile, FindNextFile и RemoveDirectory Win API. Ничего не происходит нитовым или асинхронным по поводу запуска .NET-вызовов этих вызовов API или самой реализации API.
Теперь, предположив, что это как-то проблема TRIM, вы можете отключить TRIM, открыв приветственную командную строку и используя fsutil:
fsutil behavior set disabledeletenotify 1
Чтобы включить, выполните ту же команду с параметром 0 в качестве параметра.
Для запроса используйте запрос в качестве аргумента команды:
fsutil behavior query disabledeletenotify
Ответ 3
Да, это не имеет ничего общего с диском SSD. У меня была такая же проблема, но только на клиентском ноутбуке. Я использую .NET 3.5. В моем случае в каталоге был один файл. Кажется, что CreateDirectory выполняет сначала внутренне, пока не завершится удаление.
Это был код, который хорошо работал в течение трех лет на многих компьютерах. Клиент перешел на новый ноутбук, и код для него постоянно не срабатывает. Я не могу воспроизвести сценарий на машинах разработки/тестирования с одинаковой конфигурацией.
Ответ 4
У меня была та же проблема. В итоге я удалил только содержимое каталога @"C:\test"
и копировал новые файлы в каталог. Это была моя проблема:
Использование Directory.Delete() и Directory.CreateDirectory() для перезаписывания папки
Ответ 5
Я подозреваю, что вы нашли состояние гонки в NTFS, которое ранее не было показано, так как дисков не было, которые были достаточно быстры, чтобы ударить его. Я не думаю, что TRIM имеет к этому какое-либо отношение (хотя я оставляю за собой право ошибаться!)
В любом случае, правильный способ справиться с этим состоит в том, чтобы поместить код в цикл Retry:
int retries = 3;
while(true) {
try {
doTheOperation();
break;
} catch (Exception ex) {
retries--;
if (retries == 0) {
throw;
}
Thread.Sleep(100);
continue;
}
}
Ответ 6
Если это действительно код приложения, обратите внимание, что вы действительно пытаетесь удалить каталог с именем "est"!
Побег вашего пути, чтобы быть "c:\test" или использовать @operator @ "c:\test".