[kernel32.dll]Сбой CreateHardLink с сообщением “Не удается создать файл, когда этот файл уже существует” на веб-сайте Azure во время встроенного резервного копирования RavenDB

StackOverflow https://stackoverflow.com//questions/23041289

Вопрос

Я запускаю RavenDB.Embedded версии 2.0.2370 внутри веб-сайта Azure.

Все это работает так, как ожидалось, за исключением резервной копии.Процедура резервного копирования, инициированная с помощью EmbeddableDocumentStore.DocumentDatabase.StartBackup(...) раньше все работало отлично, пока я не заметил, что последнее успешное резервное копирование датируется примерно 30 января (не спрашивайте :-)) около 18:00 UTC0 и что следующее резервное копирование, инициированное 11 февраля около 8:00 UTC0, завершилось неудачей, как и все остальные, инициированные впоследствии до сих пор.

Таким образом, похоже, что между этими двумя датами что-то должно было измениться на стороне Azure, поскольку с мая 2013 года не было никаких изменений или развертываний веб-приложения

Итак, я провел небольшое расследование, и вот мои выводы:

  • Статус резервного копирования RavenDB показывает следующее сообщение после каждого инициированного резервного копирования:

    Не удалось завершить резервное копирование, поскольку:Невозможно создать файл, если этот файл уже существует

  • После включение ведения журнала для RavenDB при запуске резервного копирования в файле журнала отображается следующая ошибка

    2014-04-12 10:38:20.5797, Ворон.Место хранения.Есент.Резервная копия.Операция резервного копирования,ошибка,не удалось завершить резервное копирование", Система.ComponentModel.Win32Exception (0x80004005):Невозможно создать файл, если этот файл уже существует в Raven.База данных.Резервная копия.DirectoryBackup.Подготовить() в Raven.Место хранения.Есент.Резервная копия.Резервная операция.Выполнить (объект игнорируется)

  • Согласно Форум веб-сайтов Azure в период между последним успешным и первым неудачным резервным копированием плановое обслуживание веб-сайтов Azure не проводилось.Были проведены в период с 9 по 15 декабря 2013 года и с 10 по 14 марта 2014 года

  • Я действительно заметил на Панель мониторинга службы Azure проблема с веб-сайтами 31 января в Западноевропейском регионе, но сайт размещен в Североевропейском регионе

  • Когда ищу (даже последнюю версию) в неисправность Код RavenDB Raven.Database.Backup.DirectoryBackup.Prepare похоже, что при вызове генерируется исключение CreateHardLink который является внешним методом, определенным как

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
    

    Странная вещь заключается в том, что код фактически проверяет наличие конкретного исключения, показанного выше (0x80004005), но исключение все равно генерируется...

    if (Marshal.GetLastWin32Error() != 0x80004005)
      throw new Win32Exception();
    
  • Итак, чтобы исключить RavenDB из уравнения, я создал следующую небольшую программу, которая имитирует то, что на самом деле делает RavenDB во время своей процедуры резервного копирования, а также после развертывания исполняемого файла и его выполнения (с помощью функции консоли, найденной на новый портал azure) на веб-сайте Azure это тоже терпит неудачу:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.InteropServices;
    
    namespace HardLinkCreationTester
    {
        public class Program
        {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
    
            static void Main()
            {
                const string sourcePath = "TestSource";
                const string targetPath = "TestTarget";
                const string tempPath = "TestTemp";
    
                try
                {
                    Directory.CreateDirectory(sourcePath);
                    Directory.CreateDirectory(targetPath);
                    Directory.CreateDirectory(tempPath);
                    File.WriteAllText(Path.Combine(sourcePath, "testfile.txt"), "Test content");
    
                    string[] sourceFilesSnapshot = Directory.GetFiles(sourcePath);
                    for (int index = 0; index < sourceFilesSnapshot.Length; index++)
                    {
                        var sourceFile = sourceFilesSnapshot[index];
                        var destFileName = Path.Combine(tempPath, Path.GetFileName(sourceFile));
    
                        if (!CreateHardLink(destFileName, sourceFile, IntPtr.Zero))
                        {
                            // 'The system cannot find the file specified' is explicitly ignored here
                            if (Marshal.GetLastWin32Error() != 0x80004005)
                                throw new Win32Exception();
                        }
                    }
                }
                finally
                {
                    Directory.Delete(sourcePath);
                    Directory.Delete(targetPath);
                    Directory.Delete(tempPath);
                }
            }
        }
    }
    
  • Чтобы исключить из уравнения и мое конкретное веб-приложение, я создал новый веб-сайт Azure и развернул тот же исполняемый файл, упомянутый выше, и это тоже терпит неудачу

  • Справедливо предположить, что они еще не запущены на ReFS (который не поддерживает жесткие ссылки) но вы все еще используете NTFS?

tl;dr

  • Что изменилось на веб-сайтах Azure, которые вызывают [kernel32.dll]CreateHardLink сбой, в то время как раньше это работало?

  • Как это можно исправить вне кода RavenDB или внутри кода RavenDB...?

Это было полезно?

Решение

Обновление: теперь эта проблема исправлена. CreateHardLink должен работать с D:\home пути.

Я думаю, что это проблема с веб-сайтами Azure.По сути, когда вы пытаетесь создать относительный путь, по умолчанию используется D:\home\.На самом деле этой папки на компьютере не существует, но Azure Websites подделывает ее для удобства.Однако здесь это, по-видимому, вызывает проблему с CreateHardLink функция.

если вы просто измените эту строку в вашем примере выше

const string tempPath = "TestTemp";

к этому

const string tempPath = @"C:\DWASFiles\Sites\<sitename>\VirtualDirectory0\site\TestTemp";

заменять <sitename> с названием вашего сайта

это сработает.

На самом деле я не очень хорошо знаком с RavenDB, но в качестве обходного пути вы можете попробовать изменить эти каталоги на полные пути, которые выглядят как приведенные выше.Тем временем я сообщу об ошибке.Дайте мне знать, сработает ли это для вас

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top