public void Test_Subspace_With_Binary_Prefix() { var subspace = new FdbSubspace(Slice.Create(new byte[] { 42, 255, 0, 127 })); Assert.That(subspace.Key.ToString(), Is.EqualTo("*<FF><00><7F>")); Assert.That(subspace.Copy(), Is.Not.SameAs(subspace)); Assert.That(subspace.Copy().Key, Is.EqualTo(subspace.Key)); // concat(Slice) should append the slice to the binary prefix directly Assert.That(subspace.Concat(Slice.FromInt32(0x01020304)).ToString(), Is.EqualTo("*<FF><00><7F><04><03><02><01>")); Assert.That(subspace.Concat(Slice.FromAscii("hello")).ToString(), Is.EqualTo("*<FF><00><7F>hello")); // pack(...) should use tuple serialization Assert.That(subspace.Pack(123).ToString(), Is.EqualTo("*<FF><00><7F><15>{")); Assert.That(subspace.Pack("hello").ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00>")); Assert.That(subspace.Pack(Slice.FromAscii("world")).ToString(), Is.EqualTo("*<FF><00><7F><01>world<00>")); Assert.That(subspace.Pack(FdbTuple.Create("hello", 123)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{")); // if we derive a tuple from this subspace, it should keep the binary prefix when converted to a key var t = subspace.Append("world", 123, false); Assert.That(t, Is.Not.Null); Assert.That(t.Count, Is.EqualTo(3)); Assert.That(t.Get <string>(0), Is.EqualTo("world")); Assert.That(t.Get <int>(1), Is.EqualTo(123)); Assert.That(t.Get <bool>(2), Is.False); var k = t.ToSlice(); Assert.That(k.ToString(), Is.EqualTo("*<FF><00><7F><02>world<00><15>{<14>")); // if we unpack the key with the binary prefix, we should get a valid tuple var t2 = subspace.Unpack(k); Assert.That(t2, Is.Not.Null); Assert.That(t2.Count, Is.EqualTo(3)); Assert.That(t2.Get <string>(0), Is.EqualTo("world")); Assert.That(t2.Get <int>(1), Is.EqualTo(123)); Assert.That(t2.Get <bool>(2), Is.False); }
public void Test_Subspace_With_Tuple_Prefix() { var subspace = new FdbSubspace(FdbTuple.Create("hello")); Assert.That(subspace.Key.ToString(), Is.EqualTo("<02>hello<00>")); Assert.That(subspace.Copy(), Is.Not.SameAs(subspace)); Assert.That(subspace.Copy().Key, Is.EqualTo(subspace.Key)); // concat(Slice) should append the slice to the tuple prefix directly Assert.That(subspace.Concat(Slice.FromInt32(0x01020304)).ToString(), Is.EqualTo("<02>hello<00><04><03><02><01>")); Assert.That(subspace.Concat(Slice.FromAscii("world")).ToString(), Is.EqualTo("<02>hello<00>world")); // pack(...) should use tuple serialization Assert.That(subspace.Pack(123).ToString(), Is.EqualTo("<02>hello<00><15>{")); Assert.That(subspace.Pack("world").ToString(), Is.EqualTo("<02>hello<00><02>world<00>")); // even though the subspace prefix is a tuple, appending to it will only return the new items var t = subspace.Append("world", 123, false); Assert.That(t, Is.Not.Null); Assert.That(t.Count, Is.EqualTo(3)); Assert.That(t.Get <string>(0), Is.EqualTo("world")); Assert.That(t.Get <int>(1), Is.EqualTo(123)); Assert.That(t.Get <bool>(2), Is.False); // but ToSlice() should include the prefix var k = t.ToSlice(); Assert.That(k.ToString(), Is.EqualTo("<02>hello<00><02>world<00><15>{<14>")); // if we unpack the key with the binary prefix, we should get a valid tuple var t2 = subspace.Unpack(k); Assert.That(t2, Is.Not.Null); Assert.That(t2.Count, Is.EqualTo(3)); Assert.That(t2.Get <string>(0), Is.EqualTo("world")); Assert.That(t2.Get <int>(1), Is.EqualTo(123)); Assert.That(t2.Get <bool>(2), Is.False); }
private async Task PushQueueAsync(IFdbTransaction tr, FdbSubspace queue, Slice taskId) { //TODO: use a high contention algo ? // - must support Push and Pop // - an empty queue must correspond to an empty subspace // get the current size of the queue var range = queue.ToRange(); var lastKey = await tr.Snapshot.GetKeyAsync(FdbKeySelector.LastLessThan(range.End)).ConfigureAwait(false); int count = lastKey < range.Begin ? 0 : queue.Unpack(lastKey).Get <int>(0) + 1; // set the value tr.Set(queue.Pack(count, GetRandomId()), taskId); }
public void Test_Subspace_With_Binary_Prefix() { var subspace = new FdbSubspace(Slice.Create(new byte[] { 42, 255, 0, 127 })); Assert.That(subspace.Key.ToString(), Is.EqualTo("*<FF><00><7F>")); Assert.That(subspace.Copy(), Is.Not.SameAs(subspace)); Assert.That(subspace.Copy().Key, Is.EqualTo(subspace.Key)); // concat(Slice) should append the slice to the binary prefix directly Assert.That(subspace.Concat(Slice.FromInt32(0x01020304)).ToString(), Is.EqualTo("*<FF><00><7F><04><03><02><01>")); Assert.That(subspace.Concat(Slice.FromAscii("hello")).ToString(), Is.EqualTo("*<FF><00><7F>hello")); // pack(...) should use tuple serialization Assert.That(subspace.Pack(123).ToString(), Is.EqualTo("*<FF><00><7F><15>{")); Assert.That(subspace.Pack("hello").ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00>")); Assert.That(subspace.Pack(Slice.FromAscii("world")).ToString(), Is.EqualTo("*<FF><00><7F><01>world<00>")); Assert.That(subspace.Pack(FdbTuple.Create("hello", 123)).ToString(), Is.EqualTo("*<FF><00><7F><02>hello<00><15>{")); // if we derive a tuple from this subspace, it should keep the binary prefix when converted to a key var t = subspace.Append("world", 123, false); Assert.That(t, Is.Not.Null); Assert.That(t.Count, Is.EqualTo(3)); Assert.That(t.Get<string>(0), Is.EqualTo("world")); Assert.That(t.Get<int>(1), Is.EqualTo(123)); Assert.That(t.Get<bool>(2), Is.False); var k = t.ToSlice(); Assert.That(k.ToString(), Is.EqualTo("*<FF><00><7F><02>world<00><15>{<14>")); // if we unpack the key with the binary prefix, we should get a valid tuple var t2 = subspace.Unpack(k); Assert.That(t2, Is.Not.Null); Assert.That(t2.Count, Is.EqualTo(3)); Assert.That(t2.Get<string>(0), Is.EqualTo("world")); Assert.That(t2.Get<int>(1), Is.EqualTo(123)); Assert.That(t2.Get<bool>(2), Is.False); }
private async Task <KeyValuePair <Slice, Slice> > FindRandomItem(IFdbTransaction tr, FdbSubspace ring) { var range = ring.ToRange(); // start from a random position around the ring Slice key = ring.Pack(GetRandomId()); // We want to find the next item in the clockwise direction. If we reach the end of the ring, we "wrap around" by starting again from the start // => So we do find_next(key <= x < MAX) and if that does not produce any result, we do a find_next(MIN <= x < key) // When the ring only contains a few items (or is empty), there is more than 50% change that we wont find anything in the first read. // To reduce the latency for this case, we will issue both range reads at the same time, and discard the second one if the first returned something. // This should reduce the latency in half when the ring is empty, or when it contains only items before the random key. var candidate = await tr.GetRange(key, range.End).FirstOrDefaultAsync(); if (!candidate.Key.IsPresent) { candidate = await tr.GetRange(range.Begin, key).FirstOrDefaultAsync(); } return(candidate); }
private async Task PushQueueAsync(IFdbTransaction tr, FdbSubspace queue, Slice taskId) { //TODO: use a high contention algo ? // - must support Push and Pop // - an empty queue must correspond to an empty subspace // get the current size of the queue var range = queue.ToRange(); var lastKey = await tr.Snapshot.GetKeyAsync(FdbKeySelector.LastLessThan(range.End)).ConfigureAwait(false); int count = lastKey < range.Begin ? 0 : queue.Unpack(lastKey).Get<int>(0) + 1; // set the value tr.Set(queue.Pack(count, GetRandomId()), taskId); }
private async Task<KeyValuePair<Slice, Slice>> FindRandomItem(IFdbTransaction tr, FdbSubspace ring) { var range = ring.ToRange(); // start from a random position around the ring Slice key = ring.Pack(GetRandomId()); // We want to find the next item in the clockwise direction. If we reach the end of the ring, we "wrap around" by starting again from the start // => So we do find_next(key <= x < MAX) and if that does not produce any result, we do a find_next(MIN <= x < key) // When the ring only contains a few items (or is empty), there is more than 50% change that we wont find anything in the first read. // To reduce the latency for this case, we will issue both range reads at the same time, and discard the second one if the first returned something. // This should reduce the latency in half when the ring is empty, or when it contains only items before the random key. var candidate = await tr.GetRange(key, range.End).FirstOrDefaultAsync(); if (!candidate.Key.IsPresent) { candidate = await tr.GetRange(range.Begin, key).FirstOrDefaultAsync(); } return candidate; }
private static Slice GetSubDirKey(FdbSubspace parent, string path) { Contract.Requires(parent != null && path != null); // for a path equal to ("foo","bar","baz") and index = -1, we need to generate (parent, SUBDIRS, "baz") // but since the last item of path can be of any type, we will use tuple splicing to copy the last item without changing its type return parent.Pack(SUBDIRS, path); }
public void Test_Subspace_With_Tuple_Prefix() { var subspace = new FdbSubspace(FdbTuple.Create("hello")); Assert.That(subspace.Key.ToString(), Is.EqualTo("<02>hello<00>")); Assert.That(subspace.Copy(), Is.Not.SameAs(subspace)); Assert.That(subspace.Copy().Key, Is.EqualTo(subspace.Key)); // concat(Slice) should append the slice to the tuple prefix directly Assert.That(subspace.Concat(Slice.FromInt32(0x01020304)).ToString(), Is.EqualTo("<02>hello<00><04><03><02><01>")); Assert.That(subspace.Concat(Slice.FromAscii("world")).ToString(), Is.EqualTo("<02>hello<00>world")); // pack(...) should use tuple serialization Assert.That(subspace.Pack(123).ToString(), Is.EqualTo("<02>hello<00><15>{")); Assert.That(subspace.Pack("world").ToString(), Is.EqualTo("<02>hello<00><02>world<00>")); // even though the subspace prefix is a tuple, appending to it will only return the new items var t = subspace.Append("world", 123, false); Assert.That(t, Is.Not.Null); Assert.That(t.Count, Is.EqualTo(3)); Assert.That(t.Get<string>(0), Is.EqualTo("world")); Assert.That(t.Get<int>(1), Is.EqualTo(123)); Assert.That(t.Get<bool>(2), Is.False); // but ToSlice() should include the prefix var k = t.ToSlice(); Assert.That(k.ToString(), Is.EqualTo("<02>hello<00><02>world<00><15>{<14>")); // if we unpack the key with the binary prefix, we should get a valid tuple var t2 = subspace.Unpack(k); Assert.That(t2, Is.Not.Null); Assert.That(t2.Count, Is.EqualTo(3)); Assert.That(t2.Get<string>(0), Is.EqualTo("world")); Assert.That(t2.Get<int>(1), Is.EqualTo(123)); Assert.That(t2.Get<bool>(2), Is.False); }
private static void SetLayer(IFdbTransaction trans, FdbSubspace subspace, Slice layer) { if (layer.IsNull) layer = Slice.Empty; trans.Set(subspace.Pack(LayerSuffix), layer); }