private static void Restore(StorageEnvironment env, IEnumerable <ZipArchiveEntry> entries, VoronPathSetting tempDir, List <IDisposable> toDispose, LowLevelTransaction txw) { try { TransactionHeader *lastTxHeader = null; var lastTxHeaderStackLocation = stackalloc TransactionHeader[1]; long lastTxId = env.HeaderAccessor.Get(x => x->TransactionId); long journalNumber = -1; foreach (var entry in entries) { switch (Path.GetExtension(entry.Name)) { case ".merged-journal": case ".journal": var jounalFileName = tempDir.Combine(entry.Name); using (var output = SafeFileStream.Create(jounalFileName.FullPath, FileMode.Create)) using (var input = entry.Open()) { output.Position = output.Length; input.CopyTo(output); } var pager = env.Options.OpenPager(jounalFileName); toDispose.Add(pager); if (long.TryParse(Path.GetFileNameWithoutExtension(entry.Name), out journalNumber) == false) { throw new InvalidOperationException("Cannot parse journal file number"); } var recoveryPager = env.Options.CreateTemporaryBufferPager(Path.Combine(tempDir.Combine(StorageEnvironmentOptions.JournalRecoveryName(journalNumber)).FullPath), env.Options.InitialFileSize ?? env.Options.InitialLogFileSize); toDispose.Add(recoveryPager); using (var reader = new JournalReader(pager, env.Options.DataPager, recoveryPager, new HashSet <long>(), new JournalInfo { LastSyncedTransactionId = lastTxId }, lastTxHeader)) { while (reader.ReadOneTransactionToDataFile(env.Options)) { lastTxHeader = reader.LastTransactionHeader; } reader.ZeroRecoveryBufferIfNeeded(reader, env.Options); if (lastTxHeader != null) { *lastTxHeaderStackLocation = *lastTxHeader; lastTxHeader = lastTxHeaderStackLocation; lastTxId = lastTxHeader->TransactionId; } } break; default: throw new InvalidOperationException("Unknown file, cannot restore: " + entry); } } if (lastTxHeader == null) { return; // there was no valid transactions, nothing to do } env.Options.DataPager.Sync(0); var root = Tree.Open(txw, null, Constants.RootTreeNameSlice, &lastTxHeader->Root); txw.UpdateRootsIfNeeded(root); txw.State.NextPageNumber = lastTxHeader->LastPageNumber + 1; txw.Commit(); env.HeaderAccessor.Modify(header => { header->TransactionId = lastTxHeader->TransactionId; header->LastPageNumber = lastTxHeader->LastPageNumber; header->Journal.LastSyncedTransactionId = lastTxHeader->TransactionId; header->Root = lastTxHeader->Root; Sparrow.Memory.Set(header->Journal.Reserved, 0, JournalInfo.NumberOfReservedBytes); header->Journal.Flags = JournalInfoFlags.None; }); } finally { toDispose.ForEach(x => x.Dispose()); try { Directory.Delete(tempDir.FullPath, true); } catch { // this is just a temporary directory, the worst case scenario is that we dont reclaim the space from the OS temp directory // if for some reason we cannot delete it we are safe to ignore it. } } }
private static void Restore(StorageEnvironment env, IEnumerable <ZipArchiveEntry> entries, string tempDir, List <IDisposable> toDispose, LowLevelTransaction txw) { try { TransactionHeader *lastTxHeader = null; long journalNumber = -1; foreach (var entry in entries) { switch (Path.GetExtension(entry.Name)) { case ".merged-journal": case ".journal": var jounalFileName = Path.Combine(tempDir, entry.Name); using (var output = new FileStream(jounalFileName, FileMode.Create)) using (var input = entry.Open()) { output.Position = output.Length; input.CopyTo(output); } var pager = env.Options.OpenPager(jounalFileName); toDispose.Add(pager); if (long.TryParse(Path.GetFileNameWithoutExtension(entry.Name), out journalNumber) == false) { throw new InvalidOperationException("Cannot parse journal file number"); } var recoveryPager = env.Options.CreateScratchPager(Path.Combine(tempDir, StorageEnvironmentOptions.JournalRecoveryName(journalNumber)), env.Options.InitialFileSize ?? env.Options.InitialLogFileSize); toDispose.Add(recoveryPager); using ( var reader = new JournalReader(pager, env.Options.DataPager, recoveryPager, 0, lastTxHeader)) { while (reader.ReadOneTransactionToDataFile(env.Options)) { lastTxHeader = reader.LastTransactionHeader; } } break; default: throw new InvalidOperationException("Unknown file, cannot restore: " + entry); } } if (lastTxHeader == null) { return; // there was no valid transactions, nothing to do } env.Options.DataPager.Sync(); var root = Tree.Open(txw, null, &lastTxHeader->Root); root.Name = Constants.RootTreeNameSlice; txw.UpdateRootsIfNeeded(root); txw.State.NextPageNumber = lastTxHeader->LastPageNumber + 1; env.Journal.Clear(txw); txw.Commit(); env.HeaderAccessor.Modify(header => { header->TransactionId = lastTxHeader->TransactionId; header->LastPageNumber = lastTxHeader->LastPageNumber; header->Journal.LastSyncedJournal = journalNumber; header->Journal.LastSyncedTransactionId = lastTxHeader->TransactionId; header->Root = lastTxHeader->Root; header->Journal.CurrentJournal = journalNumber + 1; header->Journal.JournalFilesCount = 0; }); } finally { toDispose.ForEach(x => x.Dispose()); try { Directory.Delete(tempDir, true); } catch { // this is just a temporary directory, the worst case scenario is that we dont reclaim the space from the OS temp directory // if for some reason we cannot delete it we are safe to ignore it. } } }