public void Test_FdbKeyRange_Contains() { FdbKeyRange range; // ["", "") range = FdbKeyRange.Empty; Assert.That(range.Contains(Slice.Empty), Is.False); Assert.That(range.Contains(Slice.FromAscii("\x00")), Is.False); Assert.That(range.Contains(Slice.FromAscii("hello")), Is.False); Assert.That(range.Contains(Slice.FromAscii("\xFF")), Is.False); // ["", "\xFF" ) range = FdbKeyRange.Create(Slice.Empty, Slice.FromAscii("\xFF")); Assert.That(range.Contains(Slice.Empty), Is.True); Assert.That(range.Contains(Slice.FromAscii("\x00")), Is.True); Assert.That(range.Contains(Slice.FromAscii("hello")), Is.True); Assert.That(range.Contains(Slice.FromAscii("\xFF")), Is.False); // ["\x00", "\xFF" ) range = FdbKeyRange.Create(Slice.FromAscii("\x00"), Slice.FromAscii("\xFF")); Assert.That(range.Contains(Slice.Empty), Is.False); Assert.That(range.Contains(Slice.FromAscii("\x00")), Is.True); Assert.That(range.Contains(Slice.FromAscii("hello")), Is.True); Assert.That(range.Contains(Slice.FromAscii("\xFF")), Is.False); // corner cases Assert.That(FdbKeyRange.Create(Slice.FromAscii("A"), Slice.FromAscii("A")).Contains(Slice.FromAscii("A")), Is.False, "Equal bounds"); }
public void Test_FdbKeyRange_Test() { const int BEFORE = -1, INSIDE = 0, AFTER = +1; FdbKeyRange range; // range: [ "A", "Z" ) range = FdbKeyRange.Create(Slice.FromAscii("A"), Slice.FromAscii("Z")); // Excluding the end: < "Z" Assert.That(range.Test(Slice.FromAscii("\x00"), endIncluded: false), Is.EqualTo(BEFORE)); Assert.That(range.Test(Slice.FromAscii("@"), endIncluded: false), Is.EqualTo(BEFORE)); Assert.That(range.Test(Slice.FromAscii("A"), endIncluded: false), Is.EqualTo(INSIDE)); Assert.That(range.Test(Slice.FromAscii("Z"), endIncluded: false), Is.EqualTo(AFTER)); Assert.That(range.Test(Slice.FromAscii("Z\x00"), endIncluded: false), Is.EqualTo(AFTER)); Assert.That(range.Test(Slice.FromAscii("\xFF"), endIncluded: false), Is.EqualTo(AFTER)); // Including the end: <= "Z" Assert.That(range.Test(Slice.FromAscii("\x00"), endIncluded: true), Is.EqualTo(BEFORE)); Assert.That(range.Test(Slice.FromAscii("@"), endIncluded: true), Is.EqualTo(BEFORE)); Assert.That(range.Test(Slice.FromAscii("A"), endIncluded: true), Is.EqualTo(INSIDE)); Assert.That(range.Test(Slice.FromAscii("Z"), endIncluded: true), Is.EqualTo(INSIDE)); Assert.That(range.Test(Slice.FromAscii("Z\x00"), endIncluded: true), Is.EqualTo(AFTER)); Assert.That(range.Test(Slice.FromAscii("\xFF"), endIncluded: true), Is.EqualTo(AFTER)); range = FdbKeyRange.Create(FdbTuple.Pack("A"), FdbTuple.Pack("Z")); Assert.That(range.Test(FdbTuple.Create("@")), Is.EqualTo((BEFORE))); Assert.That(range.Test(FdbTuple.Create("A")), Is.EqualTo((INSIDE))); Assert.That(range.Test(FdbTuple.Create("Z")), Is.EqualTo((AFTER))); Assert.That(range.Test(FdbTuple.Create("Z"), endIncluded: true), Is.EqualTo(INSIDE)); }
public void Test_FdbKeyRange_Disjoint() { Func <byte, byte, FdbKeyRange> range = (x, y) => FdbKeyRange.Create(Slice.FromByte(x), Slice.FromByte(y)); #region Disjoint... // [0, 1) [2, 3) // #X // #X Assert.That(range(0, 1).Disjoint(range(2, 3)), Is.True); // [2, 3) [0, 1) // #X // #X Assert.That(range(2, 3).Disjoint(range(0, 1)), Is.True); #endregion #region Not Disjoint... // [0, 1) [1, 2) // #X // #X Assert.That(range(0, 1).Disjoint(range(1, 2)), Is.False); // [1, 2) [0, 1) // #X // #X Assert.That(range(1, 2).Disjoint(range(0, 1)), Is.False); // [0, 2) [1, 3) // ##X // ##X Assert.That(range(0, 2).Disjoint(range(1, 3)), Is.False); // [1, 3) [0, 2) // ##X // ##X Assert.That(range(1, 3).Disjoint(range(0, 2)), Is.False); // [0, 1) [0, 2) // #X // ##X Assert.That(range(0, 1).Disjoint(range(0, 2)), Is.False); // [0, 2) [0, 1) // ##X // #X Assert.That(range(0, 2).Disjoint(range(0, 1)), Is.False); // [0, 2) [1, 2) // ##X // #X Assert.That(range(0, 2).Disjoint(range(1, 2)), Is.False); // [1, 2) [0, 2) // #X // ##X Assert.That(range(1, 2).Disjoint(range(0, 2)), Is.False); #endregion }
public async Task <Slice> GetKeyAsync(FdbKeySelector selector, bool snapshot, CancellationToken cancellationToken) { Contract.Requires(selector.Key.HasValue); cancellationToken.ThrowIfCancellationRequested(); CheckAccessToSystemKeys(selector.Key, end: true); //Trace.WriteLine("## GetKey " + selector + ", snapshot=" + snapshot); FdbKeyRange keyRange; lock (m_buffer) { keyRange = m_buffer.InternRangeFromKey(selector.Key); selector = new FdbKeySelector(keyRange.Begin, selector.OrEqual, selector.Offset); } // we need the read version EnsureHasReadVersion(); var results = await m_db.GetKeysAtVersion(new [] { selector }, m_readVersion.Value).ConfigureAwait(false); Contract.Assert(results != null && results.Length == 1); var result = results[0]; FdbKeyRange resultRange; int c = result.CompareTo(selector.Key); if (c == 0) { // the result is identical to the key resultRange = keyRange; result = keyRange.Begin; } else { // intern the result lock (m_buffer) { resultRange = m_buffer.InternRangeFromKey(result); result = resultRange.Begin; } } //TODO: how to merge the results with the local state mutations ? // => add values that were inserted // => remove values that were cleared // => change the value of keys that were mutated locally if (!snapshot) { lock (m_lock) { //TODO: use the result to create the conflict range (between the resolver key and the returned key) if (c == 0) { // the key itself was selected, so it can only conflict if it gets deleted by another transaction // [ result, result+\0 ) AddReadConflict_NeedsLocking(resultRange); } else if (c < 0) { // the result is before the selected key, so any change between them (including deletion of the result) will conflict // orEqual == true => [ result, key + \0 ) // orEqual == false => [ result, key ) AddReadConflict_NeedsLocking(FdbKeyRange.Create(resultRange.Begin, selector.OrEqual ? keyRange.End : keyRange.Begin)); } else { // the result is after the selected key, so any change between it and the result will conflict // orEqual == true => [ key + \0, result + \0 ) // orEqual == false => [ key , result + \0 ) AddReadConflict_NeedsLocking(FdbKeyRange.Create(selector.OrEqual ? keyRange.End : keyRange.Begin, resultRange.End)); } } } return(result); }