Fixes internal BTree key duplication.

This commit is contained in:
Ahmed Yasin Koculu
2022-08-15 03:47:39 +02:00
parent d8caaf11cb
commit f20572d1fd
3 changed files with 122 additions and 17 deletions
+23 -13
View File
@@ -1,4 +1,5 @@
using Tenray.ZoneTree.Comparers;
using Tenray.ZoneTree.Collections.BplusTree.Lock;
using Tenray.ZoneTree.Comparers;
using Tenray.ZoneTree.Serializers;
namespace Tenray.ZoneTree.UnitTests;
@@ -289,16 +290,16 @@ public class IteratorTests
zoneTree.Maintenance.DestroyTree();
}
[Test]
public void IntIntReverseIteratorParallelInserts()
[TestCase(true)]
[TestCase(false)]
public void IntIntReverseIteratorParallelInserts(bool reverse)
{
var dataPath = "data/IntIntReverseIteratorParallelInserts";
if (Directory.Exists(dataPath))
Directory.Delete(dataPath, true);
var random = new Random();
var insertCount = 100000;
var insertCount = 1000000;
var iteratorCount = 1000;
using var zoneTree = new ZoneTreeFactory<int, int>()
@@ -308,36 +309,45 @@ public class IteratorTests
.SetWriteAheadLogDirectory(dataPath)
.SetKeySerializer(new Int32Serializer())
.SetValueSerializer(new Int32Serializer())
.Configure(x =>
{
x.BTreeLockMode = BTreeLockMode.NodeLevelMonitor;
})
.OpenOrCreate();
var task = Task.Factory.StartNew(() =>
var task = Task.Run(() =>
{
Parallel.For(0, insertCount, (x) =>
{
var key = random.Next();
var key = random.Next(0, 100_000);
zoneTree.Upsert(key, key + key);
});
});
Parallel.For(0, iteratorCount, (x) =>
{
var initialCount = zoneTree.Maintenance.InMemoryRecordCount;
using var iterator = zoneTree.CreateReverseIterator(false);
var initialCount = zoneTree.Maintenance.MutableSegmentRecordCount;
using var iterator =
reverse ?
zoneTree.CreateReverseIterator(false) :
zoneTree.CreateIterator(false);
iterator.SeekFirst();
var counter = 1;
var isValidData = true;
var previousKey = int.MaxValue;
var previousKey = reverse ? int.MaxValue : int.MinValue;
while (iterator.Next())
{
var expected = iterator.CurrentKey + iterator.CurrentKey;
if (iterator.CurrentValue != expected)
isValidData = false;
if (iterator.CurrentKey >= previousKey)
if (reverse && iterator.CurrentKey >= previousKey)
throw new Exception("Reverse Iterator is not iterating in valid order.");
if (!reverse && iterator.CurrentKey <= previousKey)
throw new Exception("Iterator is not iterating in valid order.");
previousKey = iterator.CurrentKey;
++counter;
}
if (counter < initialCount)
Console.WriteLine(initialCount + " > " + counter);
Assert.That(counter, Is.GreaterThanOrEqualTo(initialCount));
Assert.That(isValidData, Is.True);
});
@@ -245,4 +245,92 @@ public class SafeBTreeTests
task.Wait();
}
[TestCase(BTreeLockMode.TopLevelReaderWriter)]
[TestCase(BTreeLockMode.TopLevelMonitor)]
[TestCase(BTreeLockMode.NodeLevelReaderWriter)]
[TestCase(BTreeLockMode.NodeLevelMonitor)]
public void IntIntDuplicateRecords(BTreeLockMode lockMode)
{
var random = new Random();
var insertCount = 1000000;
var iteratorCount = 1000;
var tree = new BTree<int, int>(new Int32ComparerAscending(), lockMode);
var task = Task.Run(() =>
{
Parallel.For(0, insertCount, (x) =>
{
var key = random.Next(0, 100000);
tree.Upsert(key, key + key, out _);
});
});
Parallel.For(0, iteratorCount, (x) =>
{
var initialCount = tree.Length;
var iterator = new BTreeSeekableIterator<int, int>(tree);
var counter = iterator.SeekBegin() ? 1 : 0;
var isValidData = true;
var previousKey = int.MinValue;
while (iterator.Next())
{
var expected = iterator.CurrentKey + iterator.CurrentKey;
if (iterator.CurrentValue != expected)
isValidData = false;
if (iterator.CurrentKey <= previousKey)
throw new Exception(
$"Iterator is not iterating in valid order.{iterator.CurrentKey} <= {previousKey}");
previousKey = iterator.CurrentKey;
++counter;
}
Assert.That(counter, Is.GreaterThanOrEqualTo(initialCount));
Assert.That(isValidData, Is.True);
});
task.Wait();
}
[TestCase(BTreeLockMode.TopLevelReaderWriter)]
[TestCase(BTreeLockMode.TopLevelMonitor)]
[TestCase(BTreeLockMode.NodeLevelReaderWriter)]
[TestCase(BTreeLockMode.NodeLevelMonitor)]
public void IntIntDuplicateReverseRecords(BTreeLockMode lockMode)
{
var random = new Random();
var insertCount = 1000000;
var iteratorCount = 1000;
var tree = new BTree<int, int>(new Int32ComparerAscending(), lockMode);
var task = Task.Run(() =>
{
Parallel.For(0, insertCount, (x) =>
{
var key = random.Next(0, 100000);
tree.Upsert(key, key + key, out _);
});
});
Parallel.For(0, iteratorCount, (x) =>
{
var initialCount = tree.Length;
var iterator = new BTreeSeekableIterator<int, int>(tree);
var counter = iterator.SeekEnd() ? 1 : 0;
var isValidData = true;
var previousKey = int.MaxValue;
while (iterator.Prev())
{
var expected = iterator.CurrentKey + iterator.CurrentKey;
if (iterator.CurrentValue != expected)
isValidData = false;
if (iterator.CurrentKey >= previousKey)
throw new Exception(
$"Reverse Iterator is not iterating in valid order.{iterator.CurrentKey} >= {previousKey}");
previousKey = iterator.CurrentKey;
++counter;
}
Assert.That(counter, Is.GreaterThanOrEqualTo(initialCount));
Assert.That(isValidData, Is.True);
});
task.Wait();
}
}
@@ -200,7 +200,8 @@ public partial class BTree<TKey, TValue>
node.WriteUnlock();
return true;
}
if (found)
++position;
var child = node.Children[position];
child.WriteLock();
if (child.IsFull)
@@ -208,7 +209,7 @@ public partial class BTree<TKey, TValue>
SplitChild(node, position, child);
child.WriteUnlock();
if (Comparer.Compare(in key, in node.Keys[position]) > 0)
if (Comparer.Compare(in key, in node.Keys[position]) >= 0)
++position;
child = node.Children[position];
@@ -240,6 +241,9 @@ public partial class BTree<TKey, TValue>
return true;
}
if (found)
++position;
var child = node.Children[position];
child.WriteLock();
if (child.IsFull)
@@ -247,7 +251,7 @@ public partial class BTree<TKey, TValue>
SplitChild(node, position, child);
child.WriteUnlock();
if (Comparer.Compare(in key, in node.Keys[position]) > 0)
if (Comparer.Compare(in key, in node.Keys[position]) >= 0)
++position;
child = node.Children[position];
@@ -282,6 +286,9 @@ public partial class BTree<TKey, TValue>
return AddOrUpdateResult.ADDED;
}
if (found)
++position;
var child = node.Children[position];
child.WriteLock();
if (child.IsFull)
@@ -289,7 +296,7 @@ public partial class BTree<TKey, TValue>
SplitChild(node, position, child);
child.WriteUnlock();
if (Comparer.Compare(in key, in node.Keys[position]) > 0)
if (Comparer.Compare(in key, in node.Keys[position]) >= 0)
++position;
child = node.Children[position];