Необычное поведение при удалении каталогов на SSD-диске - PullRequest
26 голосов
/ 17 мая 2011

Каталог 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, ОС - Windows 7 64-битная с поддержкой 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 ]

16 голосов
/ 17 мая 2011

У меня были проблемы с этим раньше, но это не относится к 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);
5 голосов
/ 17 мая 2011

После изучения System.IO.Directory с отражателем это выглядит так: .Delete - это просто оболочка для вызовов API FindFirstFile, FindNextFile и RemoveDirectory Win.Нет ничего поточного или асинхронного в вызове .Net этих вызовов API или в самой реализации API.

Теперь, предположив, что это каким-то образом проблема TRIM, вы можете отключить TRIM, открыв командную строку с повышенными привилегиями и используя fsutil:

fsutil behavior set disabledeletenotify 1

Чтобы включить, запустите ту же команду с 0 в качестве параметра.

Для запроса используйте запрос в качестве аргумента команды:

fsutil behavior query disabledeletenotify 
2 голосов
/ 06 июня 2012

Да, это не имеет никакого отношения к SSD-накопителю. У меня была такая же проблема, но только на клиентском ноутбуке. Я использую .NET 3.5. В моем случае в каталоге был один файл. Создается впечатление, что CreateDirectory сначала выполняется внутри, прежде чем удаление завершено.

Этот код хорошо работал три года на многих компьютерах. Клиент изменился на новый ноутбук, и код постоянно терпит неудачу для него. Я не могу воспроизвести сценарий на машинах разработки / тестирования с такой же конфигурацией.

1 голос
/ 24 сентября 2015

У меня была такая же проблема.В итоге я удалил только содержимое каталога @"C:\test" и скопировал новые файлы в каталог.Это была моя проблема:

Использование Directory.Delete () и Directory.CreateDirectory () для перезаписи папки

0 голосов
/ 03 декабря 2011

Если это действительно код приложения, обратите внимание, что вы действительно пытаетесь удалить каталог с именем "est"!

Выйдите из пути "c: \ test" или используйте оператор @ @ "c: \ test".

0 голосов
/ 17 мая 2011

Я подозреваю, что вы обнаружили состояние гонки в NTFS, которое ранее не отображалось, поскольку не было накопителей, которые были достаточно быстры, чтобы поразить его. Я не думаю, что TRIM имеет к этому какое-либо отношение (хотя я оставляю за собой право ошибаться!)

В любом случае, правильный способ справиться с этим - поместить код в цикл Retry:

int retries = 3;
while(true) {
    try {
        doTheOperation();
        break;
    } catch (Exception ex) {
        retries--;
        if (retries == 0) {
            throw;
        }

        Thread.Sleep(100);
        continue;
    }        
}
...