Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveRuble committed Sep 26, 2021
1 parent dd14916 commit b4541aa
Show file tree
Hide file tree
Showing 36 changed files with 2,806 additions and 0 deletions.
45 changes: 45 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Common IntelliJ Platform excludes

# User specific
**/.idea/**/workspace.xml
**/.idea/**/tasks.xml
**/.idea/shelf/*
**/.idea/dictionaries
**/.idea/httpRequests

# Sensitive or high-churn files
**/.idea/**/dataSources/
**/.idea/**/dataSources.ids
**/.idea/**/dataSources.xml
**/.idea/**/dataSources.local.xml
**/.idea/**/sqlDataSources.xml
**/.idea/**/dynamic.xml
**/.idea/**/sqldialects.xml

# Rider
# Rider auto-generates .iml files, and contentModel.xml
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml

**/*.suo
**/*.user
**/.vs/
**/[Bb]in/
**/[Oo]bj/
publish/
_UpgradeReport_Files/
[Pp]ackages/

Thumbs.db
Desktop.ini
.DS_Store

*.blob

coverage.json

.vscode/

# Snapshotter mismatches
**/__mismatch__/
13 changes: 13 additions & 0 deletions .idea/.idea.Bloomn/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/.idea.Bloomn/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions Bloomn.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bloomn", "src\Bloomn\Bloomn.csproj", "{7C864204-2CFC-4200-BCCF-0027A89C6CF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bloomn.Tests", "tests\Bloomn.Tests\Bloomn.Tests.csproj", "{171BBD20-CB99-41CD-9F23-EA7BF99241E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7C864204-2CFC-4200-BCCF-0027A89C6CF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C864204-2CFC-4200-BCCF-0027A89C6CF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C864204-2CFC-4200-BCCF-0027A89C6CF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C864204-2CFC-4200-BCCF-0027A89C6CF3}.Release|Any CPU.Build.0 = Release|Any CPU
{171BBD20-CB99-41CD-9F23-EA7BF99241E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{171BBD20-CB99-41CD-9F23-EA7BF99241E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{171BBD20-CB99-41CD-9F23-EA7BF99241E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{171BBD20-CB99-41CD-9F23-EA7BF99241E4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
2 changes: 2 additions & 0 deletions Bloomn.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bloomn/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
10 changes: 10 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#Bloomn Bloom Filter for .NET

Bloomn provides a modern, high performance bloom filter implementation.

### Features

- Provides a very low allocation API for demanding scenarios
- Provides a simpler API for simpler scenarios
- Bloom filter state can be exported, serialized, and imported
- Integrates with standard .NET dependency injection framework.
3 changes: 3 additions & 0 deletions src/Bloomn/AssemblyAttributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@


[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("Bloomn.Tests")]
169 changes: 169 additions & 0 deletions src/Bloomn/BloomFilterBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
using System;
using System.Linq;
using System.Text.Json;
using Microsoft.Extensions.Options;

namespace Bloomn
{
public interface IBloomFilterOptionsBuilder
{
IBloomFilterBuilder WithCapacityAndErrorRate(int capacity, double errorRate);

IBloomFilterBuilder WithDimensions(BloomFilterDimensions dimensions);

IBloomFilterBuilder WithScaling(double capacityScaling = 2, double errorRateScaling = 0.8);

IBloomFilterBuilder WithHasher(IKeyHasherFactory hasherFactory);
}

public interface IBloomFilterBuilder: IBloomFilterOptionsBuilder
{
IBloomFilterBuilder WithOptions(BloomFilterOptions options);

IBloomFilterBuilder WithProfile(string profile);

IBloomFilterBuilder WithState(BloomFilterState state);

IBloomFilter Build();
}

internal class BloomFilterBuilder : IBloomFilterBuilder
{
private readonly IOptionsSnapshot<BloomFilterOptions>? _optionsSnapshot;
internal BloomFilterOptions Options { get; set; }

internal BloomFilterState? State { get; set; }

public BloomFilterBuilder(IOptionsSnapshot<BloomFilterOptions> options)
{
_optionsSnapshot = options;
Options = options.Value;
}

public BloomFilterBuilder(BloomFilterOptions options)
{
Options = options;
}

public IBloomFilterBuilder WithCapacityAndErrorRate(int capacity, double errorRate)
{
return WithDimensions(BloomFilterDimensions.ForCapacityAndErrorRate(capacity, errorRate));
}

public IBloomFilterBuilder WithDimensions(BloomFilterDimensions dimensions)
{
Options.Dimensions = dimensions;
return this;
}

public IBloomFilterBuilder WithScaling(double capacityScaling = 2, double errorRateScaling = 0.8)
{
Options.ScalingParameters = new ScalingParameters()
{
MaxCapacityBehavior = MaxCapacityBehavior.Scale,
CapacityScaling = capacityScaling,
ErrorRateScaling = errorRateScaling
};
return this;
}

public IBloomFilterBuilder WithHasher(IKeyHasherFactory hasherFactory)
{
Options.SetHasher(hasherFactory);
return this;
}

public IBloomFilterBuilder WithOptions(BloomFilterOptions options)
{
Options = options;
return this;
}

public IBloomFilterBuilder WithProfile(string profile)
{
if (_optionsSnapshot == null)
{
throw new InvalidOperationException("This builder was not ");
}
Options = _optionsSnapshot.Get(profile);
return this;
}

public IBloomFilterBuilder WithState(string? serializedState)
{
if (serializedState == null)
{
return this;
}

var state = JsonSerializer.Deserialize<BloomFilterState>(serializedState);
if (state == null)
{
throw new ArgumentException("Serialized state deserialized to null.", nameof(serializedState));
}

return WithState(state);
}

public IBloomFilterBuilder WithState(BloomFilterState state)
{
State = state;
return this;
}

public IBloomFilter Build()
{
var id = State?.Id ?? Guid.NewGuid().ToString();

var configuredParameters = new BloomFilterParameters(id)
{
Dimensions = Options.Dimensions,
ScalingParameters = Options.ScalingParameters,
HashAlgorithm = Options.GetHasher().Algorithm,
};

var state = State;
if (state != null)
{
var parametersFromState = state?.Parameters;

if (parametersFromState != null)
{
var inconsistencies = parametersFromState.Diff(configuredParameters);
if (inconsistencies.Any())
{
if (Options.DiscardInconsistentState)
{
state = null;
}

throw new InvalidOperationException($"When state containing parameters are provided it must be consistent with the configured parameters. " +
$"Configured parameters: {configuredParameters}; " +
$"Parameters from state: {parametersFromState}; " +
$"Inconsistencies: {string.Join(", ", inconsistencies)}");
}
}
}

if (state == null)
{
state = new BloomFilterState()
{
Parameters = configuredParameters
};
}

if (state.Parameters == null)
{
throw new Exception("State parameters not found.");
}

if (state.Parameters.ScalingParameters.MaxCapacityBehavior == MaxCapacityBehavior.Scale)
{
return new ScalingBloomFilter(Options, state);
}

return new ClassicBloomFilter(Options, state);
}
}
}
40 changes: 40 additions & 0 deletions src/Bloomn/BloomFilterCheckRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Runtime.InteropServices;

namespace Bloomn
{
public readonly ref struct BloomFilterKey
{
public readonly ReadOnlySpan<byte> Bytes;

public BloomFilterKey(string key)
{
Bytes = MemoryMarshal.AsBytes(key.AsSpan());
}

public static implicit operator BloomFilterKey(string s) => new BloomFilterKey(s);
}

public enum BloomFilterCheckBehavior
{
CheckOnly,
PrepareForAdd,
AddImmediately
}

public readonly ref struct BloomFilterCheckRequest
{
public readonly BloomFilterKey Key;
public readonly BloomFilterCheckBehavior Behavior;

public static BloomFilterCheckRequest CheckOnly(BloomFilterKey key) => new BloomFilterCheckRequest(key, BloomFilterCheckBehavior.CheckOnly);
public static BloomFilterCheckRequest PrepareForAdd(BloomFilterKey key) => new BloomFilterCheckRequest(key, BloomFilterCheckBehavior.PrepareForAdd);
public static BloomFilterCheckRequest AddImmediately(BloomFilterKey key) => new BloomFilterCheckRequest(key, BloomFilterCheckBehavior.AddImmediately);

public BloomFilterCheckRequest(BloomFilterKey key, BloomFilterCheckBehavior behavior)
{
Key = key;
Behavior = behavior;
}
}
}
7 changes: 7 additions & 0 deletions src/Bloomn/BloomFilterConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Bloomn
{
public class BloomFilterConstants
{
public const string Murmur3HasherKey = "murmur3";
}
}
Loading

0 comments on commit b4541aa

Please sign in to comment.