|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace FASTER.core
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public unsafe partial class FasterBase
|
|
|
|
|
{
|
|
|
|
|
// Derived class facing persistence API
|
|
|
|
|
internal IndexCheckpointInfo _indexCheckpoint;
|
|
|
|
|
|
|
|
|
|
internal void TakeIndexFuzzyCheckpoint()
|
|
|
|
|
{
|
|
|
|
|
var ht_version = resizeInfo.version;
|
|
|
|
|
|
|
|
|
|
TakeMainIndexCheckpoint(ht_version,
|
|
|
|
|
_indexCheckpoint.main_ht_device,
|
|
|
|
|
out ulong ht_num_bytes_written);
|
|
|
|
|
|
|
|
|
|
var sectorSize = _indexCheckpoint.main_ht_device.SectorSize;
|
|
|
|
|
var alignedIndexSize = (uint)((ht_num_bytes_written + (sectorSize - 1)) & ~(sectorSize - 1));
|
|
|
|
|
overflowBucketsAllocator.TakeCheckpoint(_indexCheckpoint.main_ht_device, alignedIndexSize, out ulong ofb_num_bytes_written);
|
|
|
|
|
_indexCheckpoint.info.num_ht_bytes = ht_num_bytes_written;
|
|
|
|
|
_indexCheckpoint.info.num_ofb_bytes = ofb_num_bytes_written;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void TakeIndexFuzzyCheckpoint(int ht_version, IDevice device,
|
|
|
|
|
out ulong numBytesWritten, IDevice ofbdevice,
|
|
|
|
|
out ulong ofbnumBytesWritten, out int num_ofb_buckets)
|
|
|
|
|
{
|
|
|
|
|
TakeMainIndexCheckpoint(ht_version, device, out numBytesWritten);
|
|
|
|
|
var sectorSize = device.SectorSize;
|
|
|
|
|
var alignedIndexSize = (uint)((numBytesWritten + (sectorSize - 1)) & ~(sectorSize - 1));
|
|
|
|
|
overflowBucketsAllocator.TakeCheckpoint(ofbdevice, alignedIndexSize, out ofbnumBytesWritten);
|
|
|
|
|
num_ofb_buckets = overflowBucketsAllocator.GetMaxValidAddress();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal bool IsIndexFuzzyCheckpointCompleted(bool waitUntilComplete = false)
|
|
|
|
|
{
|
|
|
|
|
bool completed1 = IsMainIndexCheckpointCompleted(waitUntilComplete);
|
|
|
|
|
bool completed2 = overflowBucketsAllocator.IsCheckpointCompleted(waitUntilComplete);
|
|
|
|
|
return completed1 && completed2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Implementation of an asynchronous checkpointing scheme
|
|
|
|
|
// for main hash index of FASTER
|
|
|
|
|
private CountdownEvent mainIndexCheckpointEvent;
|
|
|
|
|
|
|
|
|
|
private void TakeMainIndexCheckpoint(int tableVersion,
|
|
|
|
|
IDevice device,
|
|
|
|
|
out ulong numBytes)
|
|
|
|
|
{
|
|
|
|
|
BeginMainIndexCheckpoint(tableVersion, device, out numBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BeginMainIndexCheckpoint(
|
|
|
|
|
int version,
|
|
|
|
|
IDevice device,
|
|
|
|
|
out ulong numBytesWritten)
|
|
|
|
|
{
|
|
|
|
|
int numChunks = 1;
|
|
|
|
|
long totalSize = state[version].size * sizeof(HashBucket);
|
|
|
|
|
Debug.Assert(totalSize < (long)uint.MaxValue); // required since numChunks = 1
|
|
|
|
|
|
|
|
|
|
uint chunkSize = (uint)(totalSize / numChunks);
|
|
|
|
|
mainIndexCheckpointEvent = new CountdownEvent(numChunks);
|
|
|
|
|
HashBucket* start = state[version].tableAligned;
|
|
|
|
|
|
|
|
|
|
numBytesWritten = 0;
|
|
|
|
|
for (int index = 0; index < numChunks; index++)
|
|
|
|
|
{
|
|
|
|
|
long chunkStartBucket = (long)start + (index * chunkSize);
|
|
|
|
|
HashIndexPageAsyncFlushResult result = default(HashIndexPageAsyncFlushResult);
|
|
|
|
|
result.chunkIndex = index;
|
|
|
|
|
device.WriteAsync((IntPtr)chunkStartBucket, numBytesWritten, chunkSize, AsyncPageFlushCallback, result);
|
|
|
|
|
numBytesWritten += chunkSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsMainIndexCheckpointCompleted(bool waitUntilComplete = false)
|
|
|
|
|
{
|
|
|
|
|
bool completed = mainIndexCheckpointEvent.IsSet;
|
|
|
|
|
if (!completed && waitUntilComplete)
|
|
|
|
|
{
|
|
|
|
|
mainIndexCheckpointEvent.Wait();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return completed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AsyncPageFlushCallback(
|
|
|
|
|
uint errorCode,
|
|
|
|
|
uint numBytes,
|
|
|
|
|
NativeOverlapped* overlap)
|
|
|
|
|
{
|
|
|
|
|
//Set the page status to flushed
|
|
|
|
|
var result = (HashIndexPageAsyncFlushResult)Overlapped.Unpack(overlap).AsyncResult;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (errorCode != 0)
|
|
|
|
|
{
|
|
|
|
|
Trace.TraceError("OverlappedStream GetQueuedCompletionStatus error: {0}", errorCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Trace.TraceError("Completion Callback error, {0}", ex.Message);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
mainIndexCheckpointEvent.Signal();
|
|
|
|
|
Overlapped.Free(overlap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|