You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/FASTER/Index/Recovery/LocalCheckpointManager.cs

206 lines
8.1 KiB

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
namespace FASTER.core
{
/// <summary>
/// Implementation of checkpoint interface for local file storage
/// </summary>
public class LocalCheckpointManager : ICheckpointManager
{
private DirectoryConfiguration directoryConfiguration;
/// <summary>
/// Create new instance of local checkpoint manager at given base directory
/// </summary>
/// <param name="CheckpointDir"></param>
public LocalCheckpointManager(string CheckpointDir)
{
directoryConfiguration = new DirectoryConfiguration(CheckpointDir);
}
/// <summary>
/// Initialize index checkpoint
/// </summary>
/// <param name="indexToken"></param>
public void InitializeIndexCheckpoint(Guid indexToken)
{
directoryConfiguration.CreateIndexCheckpointFolder(indexToken);
}
/// <summary>
/// Initialize log checkpoint (snapshot and fold-over)
/// </summary>
/// <param name="logToken"></param>
public void InitializeLogCheckpoint(Guid logToken)
{
directoryConfiguration.CreateHybridLogCheckpointFolder(logToken);
}
/// <summary>
/// Commit index checkpoint
/// </summary>
/// <param name="indexToken"></param>
/// <param name="commitMetadata"></param>
public void CommitIndexCheckpoint(Guid indexToken, byte[] commitMetadata)
{
string filename = directoryConfiguration.GetIndexCheckpointMetaFileName(indexToken);
using (var writer = new BinaryWriter(new FileStream(filename, FileMode.Create)))
{
writer.Write(commitMetadata.Length);
writer.Write(commitMetadata);
writer.Flush();
}
string completed_filename = directoryConfiguration.GetIndexCheckpointFolder(indexToken);
completed_filename += Path.DirectorySeparatorChar + "completed.dat";
using (var file = new FileStream(completed_filename, FileMode.Create))
{
file.Flush();
}
}
/// <summary>
/// Commit log checkpoint (snapshot and fold-over)
/// </summary>
/// <param name="logToken"></param>
/// <param name="commitMetadata"></param>
public void CommitLogCheckpoint(Guid logToken, byte[] commitMetadata)
{
string filename = directoryConfiguration.GetHybridLogCheckpointMetaFileName(logToken);
using (var writer = new BinaryWriter(new FileStream(filename, FileMode.Create)))
{
writer.Write(commitMetadata.Length);
writer.Write(commitMetadata);
writer.Flush();
}
string completed_filename = directoryConfiguration.GetHybridLogCheckpointFolder(logToken);
completed_filename += Path.DirectorySeparatorChar + "completed.dat";
using (var file = new FileStream(completed_filename, FileMode.Create))
{
file.Flush();
}
}
/// <summary>
/// Retrieve commit metadata for specified index checkpoint
/// </summary>
/// <param name="indexToken">Token</param>
/// <returns>Metadata, or null if invalid</returns>
public byte[] GetIndexCommitMetadata(Guid indexToken)
{
var dir = new DirectoryInfo(directoryConfiguration.GetIndexCheckpointFolder(indexToken));
if (!File.Exists(dir.FullName + Path.DirectorySeparatorChar + "completed.dat"))
return null;
string filename = directoryConfiguration.GetIndexCheckpointMetaFileName(indexToken);
using (var reader = new BinaryReader(new FileStream(filename, FileMode.Open)))
{
var len = reader.ReadInt32();
return reader.ReadBytes(len);
}
}
/// <summary>
/// Retrieve commit metadata for specified log checkpoint
/// </summary>
/// <param name="logToken">Token</param>
/// <returns>Metadata, or null if invalid</returns>
public byte[] GetLogCommitMetadata(Guid logToken)
{
var dir = new DirectoryInfo(directoryConfiguration.GetHybridLogCheckpointFolder(logToken));
if (!File.Exists(dir.FullName + Path.DirectorySeparatorChar + "completed.dat"))
return null;
string checkpointInfoFile = directoryConfiguration.GetHybridLogCheckpointMetaFileName(logToken);
using (var reader = new BinaryReader(new FileStream(checkpointInfoFile, FileMode.Open)))
{
var len = reader.ReadInt32();
return reader.ReadBytes(len);
}
}
/// <summary>
/// Provide device to store index checkpoint (including overflow buckets)
/// </summary>
/// <param name="indexToken"></param>
/// <returns></returns>
public IDevice GetIndexDevice(Guid indexToken)
{
return Devices.CreateLogDevice(directoryConfiguration.GetPrimaryHashTableFileName(indexToken), false);
}
/// <summary>
/// Provide device to store snapshot of log (required only for snapshot checkpoints)
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public IDevice GetSnapshotLogDevice(Guid token)
{
return Devices.CreateLogDevice(directoryConfiguration.GetLogSnapshotFileName(token), false);
}
/// <summary>
/// Provide device to store snapshot of object log (required only for snapshot checkpoints)
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public IDevice GetSnapshotObjectLogDevice(Guid token)
{
return Devices.CreateLogDevice(directoryConfiguration.GetObjectLogSnapshotFileName(token), false);
}
/// <summary>
/// Get latest valid checkpoint for recovery
/// </summary>
/// <param name="indexToken"></param>
/// <param name="logToken"></param>
/// <returns></returns>
public bool GetLatestCheckpoint(out Guid indexToken, out Guid logToken)
{
var indexCheckpointDir = new DirectoryInfo(directoryConfiguration.GetIndexCheckpointFolder());
var dirs = indexCheckpointDir.GetDirectories();
foreach (var dir in dirs)
{
// Remove incomplete checkpoints
if (!File.Exists(dir.FullName + Path.DirectorySeparatorChar + "completed.dat"))
{
Directory.Delete(dir.FullName, true);
}
}
var latestICFolder = indexCheckpointDir.GetDirectories().OrderByDescending(f => f.LastWriteTime).First();
if (latestICFolder == null || !Guid.TryParse(latestICFolder.Name, out indexToken))
{
throw new Exception("No valid index checkpoint to recover from");
}
var hlogCheckpointDir = new DirectoryInfo(directoryConfiguration.GetHybridLogCheckpointFolder());
dirs = hlogCheckpointDir.GetDirectories();
foreach (var dir in dirs)
{
// Remove incomplete checkpoints
if (!File.Exists(dir.FullName + Path.DirectorySeparatorChar + "completed.dat"))
{
Directory.Delete(dir.FullName, true);
}
}
var latestHLCFolder = hlogCheckpointDir.GetDirectories().OrderByDescending(f => f.LastWriteTime).First();
if (latestHLCFolder == null || !Guid.TryParse(latestHLCFolder.Name, out logToken))
{
throw new Exception("No valid hybrid log checkpoint to recover from");
}
return true;
}
}
}

Powered by TurnKey Linux.