[kernel32.dll]CreateHardLink non riesce con "Impossibile creare un file quando il file esiste già" sul sito Web di Azure durante il backup incorporato di RavenDb
-
21-12-2019 - |
Domanda
Sto eseguendo RavenDb.Embedded v2.0.2370 all'interno di un sito Web di Azure.
Tutto funziona come previsto, tranne il backup.La routine di backup è iniziata con EmbeddableDocumentStore.DocumentDatabase.StartBackup(...)
funzionava perfettamente finché non ho notato che l'ultimo backup riuscito risale intorno al 30 gennaio (non chiedere :-)) intorno alle 18:00 UTC0 e che il backup successivo avviato l'11 febbraio intorno alle 8:00 UTC0 non è riuscito, così come tutte le altre iniziate successivamente fino ad oggi.
Sembra quindi che qualcosa sia cambiato tra quelle due date da parte di Azure, poiché non ci sono state modifiche o implementazioni dell'applicazione web da maggio 2013
Quindi ho fatto qualche indagine ed ecco i miei risultati:
Lo stato del backup RavenDb mostra il seguente messaggio dopo ogni backup avviato:
Impossibile completare il backup perché:Impossibile creare un file quando il file esiste già
Dopo abilitare la registrazione per RavenDb il file di registro mostra il seguente errore durante l'esecuzione del backup
2014-04-12 10:38:20.5797,Raven.Storage.Esent.Backup.BackupOperation,Errore,Impossibile completare il backup,"System.ComponentModel.Win32Exception (0x80004005):Impossibile creare un file quando il file esiste già a Raven.Database.Backup.DirectoryBackup.Prepare() a Raven.Storage.Esent.Backup.BackupOperation.Execute(Object ignored)
Secondo il Forum dei siti Web di Azure non è stata pianificata alcuna manutenzione dei siti Web di Azure nel periodo compreso tra l'ultimo backup riuscito e il primo backup non riuscito.Ci sono stati tra il 9-15 dicembre 2013 e tra il 10-14 marzo 2014
L'ho notato sul Dashboard dei servizi di Azure un problema con i siti Web il 31 gennaio nella regione dell'Europa occidentale ma il sito è ospitato nella regione dell'Europa settentrionale
Quando cercando (anche l'ultima versione) al difettoso Codice RavenDb
Raven.Database.Backup.DirectoryBackup.Prepare
sembra che l'eccezione venga lanciata durante la chiamataCreateHardLink
che è un metodo esterno definito come[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
La cosa strana è che il codice controlla effettivamente l'eccezione specifica mostrata sopra (0x80004005), ma l'eccezione viene comunque lanciata...
if (Marshal.GetLastWin32Error() != 0x80004005) throw new Win32Exception();
Quindi, per escludere RavenDb dall'equazione, ho creato il seguente piccolo programma che simula ciò che RavenDb sta effettivamente facendo durante la sua routine di backup e dopo aver distribuito l'eseguibile ed eseguito (tramite la funzione Console presente sul nuovo portale azzurro) nel sito Web di Azure fallisce anche lui:
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); } } } }
Per escludere dall'equazione anche la mia applicazione Web specifica, ho creato un nuovo sito Web di Azure e ho distribuito lo stesso eseguibile menzionato sopra e fallisce anche lui
È giusto supporre che non siano ancora in esecuzione su ReFS (che non supporta i collegamenti fisici) ma usi ancora NTFS?
tl; dott
Cosa è cambiato nei siti Web di Azure a cui effettua una chiamata
[kernel32.dll]CreateHardLink
fallire mentre prima funzionava?Come è possibile risolvere questo problema all'esterno del codice RavenDb o all'interno del codice RavenDb...?
Soluzione
Aggiornamento: questo problema è stato risolto ora. CreateHardLink
dovrebbe lavorare con D:\home
percorsi.
Penso che sia un problema con i siti Web di Azure.Fondamentalmente quando provi a creare un percorso relativo, viene impostato per impostazione predefinita D:\home\
.Questa cartella in realtà non esiste nel computer, ma i siti Web di Azure la falsificano per comodità.Tuttavia qui sembra che il problema sia causato da CreateHardLink
funzione.
se cambi semplicemente questa riga nel tuo esempio sopra
const string tempPath = "TestTemp";
a questa
const string tempPath = @"C:\DWASFiles\Sites\<sitename>\VirtualDirectory0\site\TestTemp";
sostituire <sitename>
con il nome del tuo sito
funzionerà.
Non ho molta familiarità con RavenDb, ma per aggirare il problema puoi provare a cambiare queste directory nei percorsi completi che assomigliano a quello sopra.Nel frattempo segnalerò il bug.Fammi sapere se per te va bene