// 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 { /// <summary> /// Recovery info for FASTER Log /// </summary> internal struct FasterLogRecoveryInfo { /// <summary> /// Begin address /// </summary> public long BeginAddress; /// <summary> /// Flushed logical address /// </summary> public long FlushedUntilAddress; /// <summary> /// Persisted iterators /// </summary> public Dictionary<string, long> Iterators; /// <summary> /// Initialize /// </summary> public void Initialize() { BeginAddress = 0; FlushedUntilAddress = 0; } /// <summary> /// Initialize from stream /// </summary> /// <param name="reader"></param> 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<string, long>(); for (int i = 0; i < count; i++) { Iterators.Add(reader.ReadString(), reader.ReadInt64()); } } } /// <summary> /// Recover info from token /// </summary> /// <param name="logCommitManager"></param> /// <returns></returns> 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))); } /// <summary> /// Reset /// </summary> public void Reset() { Initialize(); } /// <summary> /// Write info to byte array /// </summary> 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(); } } /// <summary> /// Take snapshot of persisted iterators /// </summary> public void PopulateIterators() { if (FasterLogScanIterator.PersistedIterators.Count > 0) { Iterators = new Dictionary<string, long>(); foreach (var kvp in FasterLogScanIterator.PersistedIterators) { Iterators.Add(kvp.Key, kvp.Value.CurrentAddress); } } } /// <summary> /// Print checkpoint info for debugging purposes /// </summary> public void DebugPrint() { Debug.WriteLine("******** Log Commit Info ********"); Debug.WriteLine("BeginAddress: {0}", BeginAddress); Debug.WriteLine("FlushedUntilAddress: {0}", FlushedUntilAddress); } } }