Skip to content

Commit

Permalink
Guaranteed deduplication
Browse files Browse the repository at this point in the history
  • Loading branch information
rickardp committed Feb 14, 2023
1 parent ebbec8d commit 70c235f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
12 changes: 9 additions & 3 deletions src/Combination.StringPools.Tests/Test_Deduplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,16 @@ public void Equal_Strings_Deduplicated_Thread_Safe(int numThreads, int numString
var str = pool.Add(someString);
Assert.Same(pool, str.StringPool);
Assert.Equal(someString, str);
Assert.Equal(str, pool.TryGet(someString));
}
var str2 = pool.TryGet(someString);
Assert.NotNull(str2);
var str2Value = str2.Value;
if (!str.Equals(str2Value))
{
Assert.True(str.Equals(str2Value));
}
Assert.Equal(10 * (2 + stringSize), pool.UsedBytes);
Assert.Equal(str, str2);
}
});
t.Start();
threads.Add(t);
Expand Down
12 changes: 12 additions & 0 deletions src/Combination.StringPools.Tests/Test_Operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ public void Test_String_Conversion()
Assert.Equal("Hello", pool.Add("Hello").ToString());
Assert.Equal("Hello", (string)pool.Add("Hello"));
}
[Fact]
public void Test_Compare_Empty()
{
using var pool = StringPool.Utf8(4096, 1);
var s = pool.Add("foo");
Assert.NotEqual(PooledUtf8String.Empty, s);
Assert.NotEqual(s, PooledUtf8String.Empty);
Assert.False(s == PooledUtf8String.Empty);
Assert.False(PooledUtf8String.Empty == s);
Assert.True(s != PooledUtf8String.Empty);
Assert.True(PooledUtf8String.Empty != s);
}

[Fact]
public void Test_Equality_Same_Pool()
Expand Down
18 changes: 17 additions & 1 deletion src/Combination.StringPools/Utf8StringPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ PooledUtf8String IUtf8StringPool.Add(string value)

var stringHash = 0;
var didAlloc = false;
var oldSize = usedBytes;
if (deduplicationTable is not null)
{
stringHash = unchecked((int)StringHash.Compute(value));
Expand All @@ -102,6 +103,11 @@ PooledUtf8String IUtf8StringPool.Add(string value)
throw new ObjectDisposedException("String pool is already disposed");
}

if (oldSize != usedBytes && TryDeduplicate(stringHash, value, out var result))
{
return new PooledUtf8String(result);
}

Interlocked.Add(ref totalAddedBytes, structLength);
Interlocked.Add(ref addedBytes, structLength);

Expand Down Expand Up @@ -277,7 +283,7 @@ private string GetFromPool(ulong handle)
var refPool = Pools[(int)poolIndex];
if (refPool != this)
{
throw new InvalidOperationException("Internal error: Deduplicated string pool mismatch");
throw new InvalidOperationException($"Internal error: Deduplicated string pool mismatch ({index} != {poolIndex})");
}
#endif
return Encoding.UTF8.GetString(GetStringBytes(offset));
Expand Down Expand Up @@ -411,6 +417,16 @@ private void Deallocate()

internal static bool StringsEqual(ulong a, ulong b)
{
if (a == ulong.MaxValue)
{
return b == ulong.MaxValue;
}

if (b == ulong.MaxValue)
{
return false;
}

var aPoolIndex = a >> (64 - PoolIndexBits);
var bPoolIndex = b >> (64 - PoolIndexBits);
if (aPoolIndex >= (ulong)Pools.Count)
Expand Down

0 comments on commit 70c235f

Please sign in to comment.