// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #pragma warning disable 0162 using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; namespace FASTER.core { /// /// Recovery info for FASTER Log /// internal struct FasterLogRecoveryInfo { /// /// Begin address /// public long BeginAddress; /// /// Flushed logical address /// public long FlushedUntilAddress; /// /// Persisted iterators /// public Dictionary Iterators; /// /// Initialize /// public void Initialize() { BeginAddress = 0; FlushedUntilAddress = 0; } /// /// Initialize from stream /// /// public void Initialize(BinaryReader reader) { int version; long checkSum; try { version = reader.ReadInt32(); checkSum = reader.ReadInt64(); BeginAddress = reader.ReadInt64(); FlushedUntilAddress = reader.ReadInt64(); } catch (Exception e) { throw new Exception("Unable to recover from previous commit. Inner exception: " + e.ToString()); } if (version != 0) throw new Exception("Invalid version found during commit recovery"); if (checkSum != (BeginAddress ^ FlushedUntilAddress)) throw new Exception("Invalid checksum found during commit recovery"); var count = 0; try { count = reader.ReadInt32(); } catch { } if (count > 0) { Iterators = new Dictionary(); for (int i = 0; i < count; i++) { Iterators.Add(reader.ReadString(), reader.ReadInt64()); } } } /// /// Recover info from token /// /// /// internal void Recover(ILogCommitManager logCommitManager) { var metadata = logCommitManager.GetCommitMetadata(); if (metadata == null) throw new Exception("Invalid log commit metadata during recovery"); Initialize(new BinaryReader(new MemoryStream(metadata))); } /// /// Reset /// public void Reset() { Initialize(); } /// /// Write info to byte array /// public byte[] ToByteArray() { using (var ms = new MemoryStream()) { using (var writer = new BinaryWriter(ms)) { writer.Write(0); // version writer.Write(BeginAddress ^ FlushedUntilAddress); // checksum writer.Write(BeginAddress); writer.Write(FlushedUntilAddress); if (Iterators?.Count > 0) { writer.Write(Iterators.Count); foreach (var kvp in Iterators) { writer.Write(kvp.Key); writer.Write(kvp.Value); } } } return ms.ToArray(); } } /// /// Take snapshot of persisted iterators /// public void PopulateIterators() { if (FasterLogScanIterator.PersistedIterators.Count > 0) { Iterators = new Dictionary(); foreach (var kvp in FasterLogScanIterator.PersistedIterators) { Iterators.Add(kvp.Key, kvp.Value.CurrentAddress); } } } /// /// Print checkpoint info for debugging purposes /// public void DebugPrint() { Debug.WriteLine("******** Log Commit Info ********"); Debug.WriteLine("BeginAddress: {0}", BeginAddress); Debug.WriteLine("FlushedUntilAddress: {0}", FlushedUntilAddress); } } }