Skip to content

Commit

Permalink
[C#] MemOnlyCache sample: improved size tracking, including read cache (
Browse files Browse the repository at this point in the history
#800)

* Improved cache size tracking, including read cache

* Rename MemOnlyCache to ResizableCacheStore.

* update doc

* fixes

* Updates
  • Loading branch information
badrishc authored Mar 9, 2023
1 parent e48d926 commit b218ba2
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 139 deletions.
22 changes: 11 additions & 11 deletions cs/FASTER.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SecondaryReaderStore", "sam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VersionedRead", "samples\ReadAddress\VersionedRead.csproj", "{33ED9E1B-1EF0-4984-A07A-7A26C205A446}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MemOnlyCache", "samples\MemOnlyCache\MemOnlyCache.csproj", "{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncStress", "playground\AsyncStress\AsyncStress.csproj", "{9EFCF8C5-320B-473C-83DE-3815981D465B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FasterLogStress", "playground\FasterLogMLSDTest\FasterLogStress.csproj", "{E8C7FB0F-38B8-468A-B1CA-8793DF8F2693}"
Expand Down Expand Up @@ -112,6 +110,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{CEDB9572-7
..\README.md = ..\README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResizableCacheStore", "samples\ResizableCacheStore\ResizableCacheStore.csproj", "{B4A55211-5457-44B9-8BCB-A5488C994965}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -288,14 +288,6 @@ Global
{33ED9E1B-1EF0-4984-A07A-7A26C205A446}.Release|Any CPU.Build.0 = Release|x64
{33ED9E1B-1EF0-4984-A07A-7A26C205A446}.Release|x64.ActiveCfg = Release|x64
{33ED9E1B-1EF0-4984-A07A-7A26C205A446}.Release|x64.Build.0 = Release|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Debug|Any CPU.ActiveCfg = Debug|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Debug|Any CPU.Build.0 = Debug|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Debug|x64.ActiveCfg = Debug|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Debug|x64.Build.0 = Debug|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Release|Any CPU.ActiveCfg = Release|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Release|Any CPU.Build.0 = Release|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Release|x64.ActiveCfg = Release|x64
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864}.Release|x64.Build.0 = Release|x64
{9EFCF8C5-320B-473C-83DE-3815981D465B}.Debug|Any CPU.ActiveCfg = Debug|x64
{9EFCF8C5-320B-473C-83DE-3815981D465B}.Debug|Any CPU.Build.0 = Debug|x64
{9EFCF8C5-320B-473C-83DE-3815981D465B}.Debug|x64.ActiveCfg = Debug|x64
Expand Down Expand Up @@ -335,6 +327,14 @@ Global
{AF996720-DB6C-4ED7-9693-B9531F0B119A}.Release|Any CPU.Build.0 = Release|Any CPU
{AF996720-DB6C-4ED7-9693-B9531F0B119A}.Release|x64.ActiveCfg = Release|Any CPU
{AF996720-DB6C-4ED7-9693-B9531F0B119A}.Release|x64.Build.0 = Release|Any CPU
{B4A55211-5457-44B9-8BCB-A5488C994965}.Debug|Any CPU.ActiveCfg = Debug|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Debug|Any CPU.Build.0 = Debug|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Debug|x64.ActiveCfg = Debug|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Debug|x64.Build.0 = Debug|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Release|Any CPU.ActiveCfg = Release|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Release|Any CPU.Build.0 = Release|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Release|x64.ActiveCfg = Release|x64
{B4A55211-5457-44B9-8BCB-A5488C994965}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -363,12 +363,12 @@ Global
{E2A1C205-4D35-448C-A72F-B9A4AE28EB4E} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
{EBE313E5-22D2-4C74-BA1F-16B60404B335} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
{33ED9E1B-1EF0-4984-A07A-7A26C205A446} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
{998D4C78-B0C5-40FF-9BDC-716BAC8CF864} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
{9EFCF8C5-320B-473C-83DE-3815981D465B} = {E6026D6A-01C5-4582-B2C1-64751490DABE}
{E8C7FB0F-38B8-468A-B1CA-8793DF8F2693} = {E6026D6A-01C5-4582-B2C1-64751490DABE}
{A265D9D2-3FEA-48BB-B1CC-273ECFEA0611} = {E6026D6A-01C5-4582-B2C1-64751490DABE}
{DC3E0640-9A36-43D0-AA37-A1B61B0BFBC9} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
{AF996720-DB6C-4ED7-9693-B9531F0B119A} = {5E4C9997-3350-4761-9FC9-F27649848B1D}
{B4A55211-5457-44B9-8BCB-A5488C994965} = {62BC1134-B6E1-476A-B894-7CA278A8B6DE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A0750637-2CCB-4139-B25E-F2CE740DCFAC}
Expand Down
108 changes: 0 additions & 108 deletions cs/samples/MemOnlyCache/CacheSizeTracker.cs

This file was deleted.

101 changes: 101 additions & 0 deletions cs/samples/ResizableCacheStore/CacheSizeTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using FASTER.core;
using System;

namespace ResizableCacheStore
{
/// <summary>
/// Cache size tracker
/// </summary>
public class CacheSizeTracker
{
readonly FasterKV<CacheKey, CacheValue> store;

/// <summary>
/// Total size (bytes) used by FASTER including index and log
/// </summary>
public long TotalSizeBytes =>
IndexSizeBytes +
mainLog.TotalSizeBytes +
(readCache != null ? readCache.TotalSizeBytes : 0);

public long IndexSizeBytes =>
store.IndexSize * 64 +
store.OverflowBucketCount * 64;

public long LogSizeBytes => mainLog.TotalSizeBytes;
public long ReadCacheSizeBytes => readCache != null ? readCache.TotalSizeBytes : 0;

readonly LogSizeTracker<CacheKey, CacheValue> mainLog;
readonly LogSizeTracker<CacheKey, CacheValue> readCache;

public void PrintStats()
{
Console.WriteLine("Sizes: [store]: {0,8:N2}KB [index]: {1,9:N2}KB [hylog]: {2,8:N2}KB ({3,7} objs) [rcach]: {4,9:N2}KB ({5,7} objs)",
TotalSizeBytes / 1024.0,
IndexSizeBytes / 1024.0,
LogSizeBytes / 1024.0,
mainLog.NumRecords,
ReadCacheSizeBytes / 1024.0,
readCache != null ? readCache.NumRecords : 0
);
}

/// <summary>
/// Class to track and update cache size
/// </summary>
/// <param name="store">FASTER store instance</param>
/// <param name="targetMemoryBytes">Initial target memory size of FASTER in bytes</param>
public CacheSizeTracker(FasterKV<CacheKey, CacheValue> store, long targetMemoryBytes = long.MaxValue)
{
this.store = store;
this.mainLog = new LogSizeTracker<CacheKey, CacheValue>(store.Log, "mnlog");
if (store.ReadCache != null)
this.readCache = new LogSizeTracker<CacheKey, CacheValue>(store.ReadCache, "readc");

if (targetMemoryBytes < long.MaxValue)
{
Console.WriteLine("**** Setting initial target memory: {0,11:N2}KB", targetMemoryBytes / 1024.0);
SetTargetSizeBytes(targetMemoryBytes);
}

PrintStats();
}

/// <summary>
/// Set target total memory size (in bytes) for the FASTER store
/// </summary>
/// <param name="newTargetSize">Target size</param>
public void SetTargetSizeBytes(long newTargetSize)
{
// In this sample, we split the residual space equally between the log and the read cache
long residual = newTargetSize - IndexSizeBytes;

if (residual > 0)
{
if (readCache == null)
mainLog.SetTargetSizeBytes(residual);
else
{
mainLog.SetTargetSizeBytes(residual / 2);
readCache.SetTargetSizeBytes(residual / 2);
}
}
}


/// <summary>
/// Add to the tracked size of FASTER. This is called by IFunctions as well as the subscriber to evictions (OnNext)
/// </summary>
/// <param name="size"></param>
public void AddTrackedSize(int size, bool isReadCache = false)
{
if (isReadCache)
readCache.AddTrackedSize(size);
else
mainLog.AddTrackedSize(size);
}
}
}
10 changes: 10 additions & 0 deletions cs/samples/ResizableCacheStore/ISizeTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

namespace ResizableCacheStore
{
public interface ISizeTracker
{
int GetSize { get; }
}
}
115 changes: 115 additions & 0 deletions cs/samples/ResizableCacheStore/LogSizeTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using FASTER.core;
using System;
using System.Threading;

namespace ResizableCacheStore
{
public class LogSizeTracker<TCacheKey, TCacheValue> : IObserver<IFasterScanIterator<TCacheKey, TCacheValue>>
where TCacheKey : ISizeTracker
where TCacheValue : ISizeTracker
{
readonly string name;

/// <summary>
/// Number of records in the log
/// </summary>
public int NumRecords;

/// <summary>
/// Total size occupied by log, including heap
/// </summary>
public long TotalSizeBytes => Log.MemorySizeBytes + heapSize;

/// <summary>
/// Target size request for FASTER
/// </summary>
public long TargetSizeBytes { get; private set; }


int heapSize;
readonly LogAccessor<TCacheKey, TCacheValue> Log;

public LogSizeTracker(LogAccessor<TCacheKey, TCacheValue> log, string name)
{
this.name = name;
Log = log;

// Register subscriber to receive notifications of log evictions from memory
Log.SubscribeEvictions(this);
}

/// <summary>
/// Add to the tracked size of FASTER. This is called by IFunctions as well as the subscriber to evictions (OnNext)
/// </summary>
/// <param name="size"></param>
public void AddTrackedSize(int size)
{
Interlocked.Add(ref heapSize, size);
if (size > 0) Interlocked.Increment(ref NumRecords);
else Interlocked.Decrement(ref NumRecords);
}

/// <summary>
/// Set target total memory size (in bytes) for the FASTER store
/// </summary>
/// <param name="newTargetSize">Target size</param>
public void SetTargetSizeBytes(long newTargetSize)
{
TargetSizeBytes = newTargetSize;
AdjustAllocation();
}
public void OnNext(IFasterScanIterator<TCacheKey, TCacheValue> iter)
{
int size = 0;
int count = 0;
while (iter.GetNext(out RecordInfo info, out TCacheKey key, out TCacheValue value))
{
size += key.GetSize;
count++;
if (!info.Tombstone) // ignore deleted values being evicted (they are accounted for by ConcurrentDeleter)
size += value.GetSize;
}
Interlocked.Add(ref heapSize, -size);
Interlocked.Add(ref NumRecords, -count);
AdjustAllocation();
}

public void OnCompleted() { }

public void OnError(Exception error) { }

void AdjustAllocation()
{
const long Delta = 1L << 15;
if (TotalSizeBytes > TargetSizeBytes + Delta)
{
while (TotalSizeBytes > TargetSizeBytes + Delta)
{
if (Log.AllocatedPageCount > Log.BufferSize - Log.EmptyPageCount + 1)
{
// Console.WriteLine($"{name}: {Log.EmptyPageCount} (wait++)");
return; // wait for allocation to stabilize
}
Log.EmptyPageCount++;
// Console.WriteLine($"{name}: {Log.EmptyPageCount} (++)");
}
}
else if (TotalSizeBytes < TargetSizeBytes - Delta)
{
while (TotalSizeBytes < TargetSizeBytes - Delta)
{
if (Log.AllocatedPageCount < Log.BufferSize - Log.EmptyPageCount - 1)
{
// Console.WriteLine($"{name}: {Log.EmptyPageCount} (wait--)");
return; // wait for allocation to stabilize
}
Log.EmptyPageCount--;
// Console.WriteLine($"{name}: {Log.EmptyPageCount} (--)");
}
}
}
}
}
Loading

0 comments on commit b218ba2

Please sign in to comment.