[kernel32.dll]Сбой CreateHardLink с сообщением “Не удается создать файл, когда этот файл уже существует” на веб-сайте Azure во время встроенного резервного копирования RavenDB
-
21-12-2019 - |
Вопрос
Я запускаю 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, но в качестве обходного пути вы можете попробовать изменить эти каталоги на полные пути, которые выглядят как приведенные выше.Тем временем я сообщу об ошибке.Дайте мне знать, сработает ли это для вас