[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

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

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 chiamata CreateHardLink 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...?

È stato utile?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top