예제 #1
0
		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;
			}
		}
예제 #2
0
		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;
			}
		}