Skip to content

Add CF commands #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/NRedisStack.Core/Bloom/BloomCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public bool Add(RedisKey key, RedisValue item)
/// <param name="key">The name of the filter.</param>
/// <param name="item">The item to check for.</param>
/// <returns><see langword="true"/> means the item may exist in the filter,
/// and <see langword="false"/> means the item may exist in the filter.</returns>
/// and <see langword="false"/> means it does not exist in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.exists"/></remarks>
public bool Exists(RedisKey key, RedisValue item)
{
Expand All @@ -41,7 +41,7 @@ public bool Exists(RedisKey key, RedisValue item)
/// Return information about a bloom filter.
/// </summary>
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Array with information of the filter.</returns>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.info"/></remarks>
public BloomInformation? Info(RedisKey key)
{
Expand Down
248 changes: 248 additions & 0 deletions src/NRedisStack.Core/CuckooFilter/CuckooCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
using NRedisStack.Core.CuckooFilter.DataTypes;
using NRedisStack.Core.Literals;
using StackExchange.Redis;
namespace NRedisStack.Core
{

public class CuckooCommands
{
IDatabase _db;
public CuckooCommands(IDatabase db)
{
_db = db;
}

/// <summary>
/// Adds an item to a Cuckoo Filter.
/// </summary>
/// <param name="key">The key under which the filter is found.</param>
/// <param name="item">The item to add.</param>
/// <returns><see langword="true"/> if the item did not exist in the filter, <see langword="false"/> otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.add"/></remarks>
public bool Add(RedisKey key, RedisValue item)
{
return _db.Execute(CF.ADD, key, item).ToString() == "1";
}

/// <summary>
/// Adds an item to a Cuckoo Filter if the item did not exist previously.
/// </summary>
/// <param name="key">The key under which the filter is found.</param>
/// <param name="item">The item to add.</param>
/// <returns><see langword="true"/> if the item did not exist in the filter, <see langword="false"/> otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.addnx"/></remarks>
public bool AddNX(RedisKey key, RedisValue item)
{
return _db.Execute(CF.ADDNX, key, item).ToString() == "1";
}

/// <summary>
/// Returns the number of times an item may be in the filter.
/// </summary>
/// <param name="key">The name of the filter</param>
/// <param name="item">The item to count.</param>
/// <returns>the count of possible matching copies of the item in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.count"/></remarks>
public long Count(RedisKey key, RedisValue item)
{
return ResponseParser.ToLong(_db.Execute(CF.COUNT, key, item));
}

/// <summary>
/// Deletes an item from the Cuckoo Filter.
/// </summary>
/// <param name="key">The name of the filter</param>
/// <param name="item">The item to delete from the filter.</param>
/// <returns>see langword="true"/> if the item has been deleted from the filter, <see langword="false"/> otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.del"/></remarks>
public bool Del(RedisKey key, RedisValue item)
{
return _db.Execute(CF.DEL, key, item).ToString() == "1";
}

/// <summary>
/// Checks whether an item exist in the Cuckoo Filter or not.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="item">The item to check for.</param>
/// <returns><see langword="true"/> means the item may exist in the filter,
/// and <see langword="false"/> means it does not exist in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.exists"/></remarks>
public bool Exists(RedisKey key, RedisValue item)
{
return _db.Execute(CF.EXISTS, key, item).ToString() == "1";
}

/// <summary>
/// Return information about a Cuckoo filter.
/// </summary>
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.info"/></remarks>
public CuckooInformation? Info(RedisKey key)
{
var info = _db.Execute(CF.INFO, key);
return ResponseParser.ToCuckooInfo(info);
}

/// <summary>
/// Adds one or more items to a Cuckoo Filter. A filter will be created if it does not exist.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to add.</param>
/// <param name="capacity">(Optional) Specifies the desired capacity for the filter to be created.</param>
/// <param name="nocreate">(Optional) <see langword="true"/> to indicates that the
/// <returns>An array of booleans.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.insert"/></remarks>
public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));

List<object> args = new List<object> { key };

if (capacity != null)
{
args.Add(CuckooArgs.CAPACITY);
args.Add(capacity);
}

if (nocreate)
{
args.Add(CuckooArgs.NOCREATE);
}

args.Add(CuckooArgs.ITEMS);
foreach (var item in items)
{
args.Add(item);
}

return ResponseParser.ToBooleanArray(_db.Execute(CF.INSERT, args));
}

/// <summary>
/// Adds one or more items to a Cuckoo Filter if the items did not exist previously.
/// A filter will be created if it does not exist.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to add.</param>
/// <param name="capacity">(Optional) Specifies the desired capacity for the filter to be created.</param>
/// <param name="nocreate">(Optional) <see langword="true"/> to indicates that the
/// <returns>An array of booleans.where <see langword="true"/> means the item has been added to the filter,
/// and <see langword="false"/> mean, the item already existed</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.insertnx"/></remarks>
public bool[] InsertNX(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));

List<object> args = new List<object> { key };

if (capacity != null)
{
args.Add(CuckooArgs.CAPACITY);
args.Add(capacity);
}

if (nocreate)
{
args.Add(CuckooArgs.NOCREATE);
}

args.Add(CuckooArgs.ITEMS);
foreach (var item in items)
{
args.Add(item);
}

return ResponseParser.ToBooleanArray(_db.Execute(CF.INSERTNX, args));
}

/// <summary>
/// Restores a filter previosly saved using SCANDUMP.
/// </summary>
/// <param name="key">Name of the key to restore.</param>
/// <param name="iterator">Iterator value associated with data (returned by SCANDUMP).</param>
/// <param name="data">Current data chunk (returned by SCANDUMP).</param>
/// <returns>Array with information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.loadchunk"/></remarks>
public bool LoadChunk(RedisKey key, long iterator, Byte[] data)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(CF.LOADCHUNK, key, iterator, data));
}

/// <summary>
/// Checks whether one or more items may exist in the a Cuckoo Filter.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to check.</param>
/// <returns>An array of booleans, for each item <see langword="true"/> means the item may exist in the filter,
/// and <see langword="false"/> means the item may exist in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.mexists"/></remarks>
public bool[] MExists(RedisKey key, RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));

List<object> args = new List<object> { key };

foreach (var item in items)
{
args.Add(item);
}

return ResponseParser.ToBooleanArray(_db.Execute(CF.MEXISTS, args));
}

/// <summary>
/// Creates a new Cuckoo Filter.
/// </summary>
/// <param name="key">The key under which the filter is found.</param>
/// <param name="capacity">The number of entries intended to be added to the filter.</param>
/// <param name="bucketSize">Number of items in each bucket.</param>
/// <param name="maxIterations">Number of attempts to swap items between buckets before
/// declaring filter as full and creating an additional filter.</param>
/// <param name="expansion">(Optional) When capacity is reached, an additional sub-filter is
/// created in size of the last sub-filter multiplied by expansion.</param>
/// <returns><see langword="true"/> if executed correctly, <see langword="false"/> otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.reserve"/></remarks>
public bool Reserve(RedisKey key, long capacity,
long? bucketSize = null, int? maxIterations = null, int? expansion = null)
{
List<object> args = new List<object> { key, capacity };

if (bucketSize != null)
{
args.Add(CuckooArgs.BUCKETSIZE);
args.Add(bucketSize);
}

if (maxIterations != null)
{
args.Add(CuckooArgs.MAXITERATIONS);
args.Add(maxIterations);
}

if (expansion != null)
{
args.Add(CuckooArgs.EXPANSION);
args.Add(expansion);
}

return ResponseParser.ParseOKtoBoolean(_db.Execute(CF.RESERVE, args));
}

/// <summary>
/// Begins an incremental save of the Cuckoo Filter.
/// </summary>
/// <param name="key">Name of the filter.</param>
/// <param name="iterator">Iterator value; either 0 or the iterator from a previous invocation of this command.</param>
/// <returns>Tuple of iterator and data.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.scandump"/></remarks>
public Tuple<long,Byte[]>? ScanDump(RedisKey key, long iterator)
{
return ResponseParser.ToScanDumpTuple(_db.Execute(CF.SCANDUMP, key, iterator));
}
}
}
32 changes: 32 additions & 0 deletions src/NRedisStack.Core/CuckooFilter/DataTypes/CuckooInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace NRedisStack.Core.CuckooFilter.DataTypes
{
/// <summary>
/// This class represents the response for CF.INFO command.
/// This object has Read-only properties and cannot be generated outside a CF.INFO response.
/// </summary>
public class CuckooInformation
{
public long Size { get; private set; }
public long NumberOfBuckets { get; private set; }
public long NumberOfFilter { get; private set; }
public long NumberOfItemsInserted { get; private set; }
public long NumberOfItemsDeleted { get; private set; }
public long BucketSize { get; private set; }
public long ExpansionRate { get; private set; }
public long MaxIteration { get; private set; }

internal CuckooInformation(long size, long numberOfBuckets, long numberOfFilter,
long numberOfItemsInserted, long numberOfItemsDeleted,
long bucketSize, long expansionRate, long maxIteration)
{
Size = size;
NumberOfBuckets = numberOfBuckets;
NumberOfFilter = numberOfFilter;
NumberOfItemsInserted = numberOfItemsInserted;
NumberOfItemsDeleted = numberOfItemsDeleted;
BucketSize = bucketSize;
ExpansionRate = expansionRate;
MaxIteration = maxIteration;
}
}
}
12 changes: 12 additions & 0 deletions src/NRedisStack.Core/CuckooFilter/Literals/CommandArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace NRedisStack.Core.Literals
{
internal class CuckooArgs
{
public static string CAPACITY => "CAPACITY";
public static string EXPANSION => "EXPANSION";
public static string NOCREATE => "NOCREATE";
public static string ITEMS => "ITEMS";
public static string BUCKETSIZE => "BUCKETSIZE";
public static string MAXITERATIONS => "MAXITERATIONS";
}
}
18 changes: 18 additions & 0 deletions src/NRedisStack.Core/CuckooFilter/Literals/Commands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace NRedisStack.Core.Literals
{
internal class CF
{
public static string RESERVE => "CF.RESERVE";
public static string ADD => "CF.ADD";
public static string ADDNX => "CF.ADDNX";
public static string INSERT => "CF.INSERT";
public static string INSERTNX => "CF.INSERTNX";
public static string EXISTS => "CF.EXISTS";
public static string MEXISTS => "CF.MEXISTS";
public static string DEL => "CF.DEL";
public static string COUNT => "CF.COUNT";
public static string SCANDUMP => "CF.SCANDUMP";
public static string LOADCHUNK => "CF.LOADCHUNK";
public static string INFO => "CF.INFO";
}
}
14 changes: 14 additions & 0 deletions src/NRedisStack.Core/ModulPrefixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public static class ModulPrefixes
static bool bloomCreated = false;
static BloomCommands bloomCommands;

static bool cuckooCreated = false;
static CuckooCommands cuckooCommands;

static bool searchCreated = false;
static SearchCommands searchCommands;

Expand All @@ -27,6 +30,17 @@ static public BloomCommands BF(this IDatabase db)
return bloomCommands;
}

static public CuckooCommands CF(this IDatabase db)
{
if (!cuckooCreated)
{
cuckooCommands = new CuckooCommands(db);
cuckooCreated = true;
}

return cuckooCommands;
}

static public SearchCommands FT(this IDatabase db)
{
if (!searchCreated)
Expand Down
Loading