public void Recover() { string currentManifest; using (var currentFile = storageContext.FileSystem.OpenForReading(storageContext.FileSystem.GetCurrentFileName())) using (var reader = new StreamReader(currentFile)) { currentManifest = reader.ReadToEnd(); } if (string.IsNullOrEmpty(currentManifest)) { throw new FormatException("CURRENT file should not be empty."); } log.Info("Current manifect is: {0}", currentManifest); using (var manifestFile = storageContext.FileSystem.OpenForReading(currentManifest)) { var logReader = new LogReader(manifestFile, true, 0, storageContext.Options.BufferPool); var builder = new Builder(storageContext, this, current); ulong? nextFileFromManifest = null; ulong? lastSequenceFromManifest = null; ulong? logNumberFromManifest = null; ulong? prevLogNumberFromManifest = null; Stream recordStream; while (logReader.TryReadRecord(out recordStream)) { VersionEdit edit; using (recordStream) { edit = VersionEdit.DecodeFrom(recordStream); } if (log.IsDebugEnabled) log.Debug("Read version edit with the following information:\r\n{0}", edit.DebugInfo); if (edit.Comparator != storageContext.Options.Comparator.Name) { throw new InvalidOperationException( string.Format("Decoded version edit comparator '{0}' does not match '{1}' that is currently in use.", edit.Comparator, storageContext.Options.Comparator.Name)); } builder.Apply(edit); if (edit.NextFileNumber.HasValue) { nextFileFromManifest = edit.NextFileNumber; } if (edit.PrevLogNumber.HasValue) { prevLogNumberFromManifest = edit.PrevLogNumber; } if (edit.LogNumber.HasValue) { logNumberFromManifest = edit.LogNumber; } if (edit.LastSequence.HasValue) { lastSequenceFromManifest = edit.LastSequence; } } if (nextFileFromManifest == null) { throw new ManifestFileException("No NextFileNumber entry"); } if (logNumberFromManifest == null) { throw new ManifestFileException("No LogNumber entry"); } if (lastSequenceFromManifest == null) { throw new ManifestFileException("No LastSequenceNumber entry"); } if (prevLogNumberFromManifest == null) { prevLogNumberFromManifest = 0; } MarkFileNumberUsed(prevLogNumberFromManifest.Value); MarkFileNumberUsed(logNumberFromManifest.Value); var version = new Version(storageContext, this); builder.SaveTo(version); Version.Finalize(version); AppendVersion(version); ManifestFileNumber = nextFileFromManifest.Value; NextFileNumber = nextFileFromManifest.Value + 1; LastSequence = lastSequenceFromManifest.Value; LogNumber = logNumberFromManifest.Value; PrevLogNumber = prevLogNumberFromManifest.Value; } }
public async Task LogAndApplyAsync(VersionEdit edit, AsyncLock.LockScope locker) { string newManifestFile = null; try { Version version; using (await locker.LockAsync()) { if (!edit.LogNumber.HasValue) edit.SetLogNumber(VersionSet.LogNumber); else if (edit.LogNumber < VersionSet.LogNumber || edit.LogNumber >= VersionSet.NextFileNumber) throw new InvalidOperationException("LogNumber"); if (!edit.PrevLogNumber.HasValue) edit.SetPrevLogNumber(VersionSet.PrevLogNumber); edit.SetNextFile(VersionSet.NextFileNumber); edit.SetLastSequence(VersionSet.LastSequence); version = new Version(this, VersionSet); var builder = new Builder(this, VersionSet, VersionSet.Current); builder.Apply(edit); builder.SaveTo(version); Version.Finalize(version); // Initialize new descriptor log file if necessary by creating // a temporary file that contains a snapshot of the current version. if (DescriptorLogWriter == null) { // No reason to unlock *mu here since we only hit this path in the // first call to LogAndApply (when opening the database). newManifestFile = FileSystem.DescriptorFileName(VersionSet.ManifestFileNumber); edit.SetNextFile(VersionSet.NextFileNumber); var descriptorFile = FileSystem.NewWritable(newManifestFile); DescriptorLogWriter = new LogWriter(FileSystem, descriptorFile, Options.BufferPool); Snapshooter.WriteSnapshot(DescriptorLogWriter, VersionSet); } } // Write new record to MANIFEST log edit.EncodeTo(DescriptorLogWriter); // If we just created a new descriptor file, install it by writing a // new CURRENT file that points to it. if (!string.IsNullOrEmpty(newManifestFile)) { SetCurrentFile(VersionSet.ManifestFileNumber); // No need to double-check MANIFEST in case of error since it // will be discarded below. } using (await locker.LockAsync()) { // Install the new version VersionSet.AppendVersion(version); VersionSet.SetLogNumber(edit.LogNumber.Value); VersionSet.SetPrevLogNumber(edit.PrevLogNumber.Value); } } catch (Exception) { if (!string.IsNullOrEmpty(newManifestFile)) { if (DescriptorLogWriter != null) { DescriptorLogWriter.Dispose(); DescriptorLogWriter = null; } FileSystem.DeleteFile(newManifestFile); } throw; } }