protected override bool RegisterGetPeersMessage(byte[] infoHash, DhtNode node, out TransactionId msgId) { var nodeId = (ulong)node.CompactEndPoint().ToInt64(); lock (this) { _index++; if (_index >= _bucketArray.Length) { _index = 0; } } var nowTick = DateTime.Now.Ticks; if (nowTick - _lastClearTime >= _clearDuration) { lock (this) { if (nowTick - _lastClearTime >= _clearDuration) { _treeStore.Clear(); _lastClearTime = nowTick; } } } msgId = _bucketArray[_index]; var path = nodeId << 16 | (uint)(msgId[0] << 8) | msgId[1]; return(_treeStore.TryAdd(path, infoHash)); }
public void TestAtomicAdd() { using (BPlusTree <int, string> data = Create(Options)) { data.EnableCount(); int[] counter = new int[] { -1 }; for (int i = 0; i < 100; i++) { Assert.IsTrue(data.TryAdd(i, k => (++counter[0]).ToString())); } Assert.AreEqual(100, data.Count); Assert.AreEqual(100, counter[0] + 1); //Inserts of existing keys will not call method Assert.IsFalse(data.TryAdd(50, k => { throw new InvalidOperationException(); })); Assert.AreEqual(100, data.Count); } }
public void TestCounts() { using (BPlusTree <int, string> data = Create(Options)) { Assert.AreEqual(int.MinValue, data.Count); data.EnableCount(); Assert.AreEqual(0, data.Count); Assert.IsTrue(data.TryAdd(1, "test")); Assert.AreEqual(1, data.Count); Assert.IsTrue(data.TryAdd(2, "test")); Assert.AreEqual(2, data.Count); Assert.IsFalse(data.TryAdd(2, "test")); Assert.AreEqual(2, data.Count); Assert.IsTrue(data.Remove(1)); Assert.AreEqual(1, data.Count); Assert.IsTrue(data.Remove(2)); Assert.AreEqual(0, data.Count); } }
public void TestTryRoutines() { using (BPlusTree <int, string> data = Create(Options)) { Assert.IsTrue(data.TryAdd(1, "a")); Assert.IsFalse(data.TryAdd(1, "a")); Assert.IsTrue(data.TryUpdate(1, "a")); Assert.IsTrue(data.TryUpdate(1, "c")); Assert.IsTrue(data.TryUpdate(1, "d", "c")); Assert.IsFalse(data.TryUpdate(1, "f", "c")); Assert.AreEqual("d", data[1]); Assert.IsTrue(data.TryUpdate(1, "a", data[1])); Assert.AreEqual("a", data[1]); Assert.IsFalse(data.TryUpdate(2, "b")); string val; Assert.IsTrue(data.TryRemove(1, out val) && val == "a"); Assert.IsFalse(data.TryRemove(2, out val)); Assert.AreNotEqual(val, "a"); } }
public void TestDeleteUnderlyingFile() { try { using (BPlusTree <int, string> tree = new BPlusTree <int, string>(Options)) { Assert.IsTrue(tree.TryAdd(1, "hi")); TempFile.Delete(); } Assert.Fail(); } catch (IOException) { } }
void AddRandomKeys(int count, Dictionary <int, string> keys, BPlusTree <int, string> data) { Stopwatch time = new Stopwatch(); time.Start(); for (int i = 0; i < count; i++) { int key = Random.Next(int.MaxValue); if (data.TryAdd(key, key.ToString())) { keys.Add(key, key.ToString()); } } Trace.TraceInformation("Added {0} in {1}", count, time.ElapsedMilliseconds); }
public void TestErrorsOnInsertAndDelete() { const int CountPerThread = 100; BPlusTree <KeyInfo, DataValue> .OptionsV2 options = new BPlusTree <KeyInfo, DataValue> .OptionsV2( new KeyInfoSerializer(), new DataValueSerializer(), new KeyInfoComparer()); options.CalcBTreeOrder(32, 300); options.FileName = TempFile.TempPath; options.CreateFile = CreatePolicy.Always; using (BPlusTree <KeyInfo, DataValue> dictionary = new BPlusTree <KeyInfo, DataValue>(options)) using (WorkQueue work = new WorkQueue(Environment.ProcessorCount)) { Exception lastError = null; work.OnError += delegate(object o, ErrorEventArgs e) { lastError = e.GetException(); }; for (int i = 0; i < Environment.ProcessorCount; i++) { work.Enqueue(new ThreadedTest(dictionary, CountPerThread).Run); } for (int i = 0; i < CountPerThread; i++) { if (i % 2 == 0) { try { dictionary.TryAdd(new KeyInfo(Guid.NewGuid(), i), k => { throw new ExpectedException(); }); } catch { } } else { try { dictionary.TryRemove(dictionary.First().Key, (k, v) => { throw new ExpectedException(); }); } catch { } } } Assert.IsTrue(work.Complete(true, 60000)); Assert.IsNull(lastError, "Exception raised in worker: {0}", lastError); } }
public void TestDeleteAfterGarbageCollection() { System.Threading.ThreadStart fn = delegate() { BPlusTree <int, string> tree = new BPlusTree <int, string>(Options); Assert.IsTrue(tree.TryAdd(1, "hi")); tree = null; }; fn(); //Allow the GC to collect the BTree System.Threading.Thread.Sleep(10); GC.GetTotalMemory(true); GC.WaitForPendingFinalizers(); //Make sure the file has been released TempFile.Delete(); }
public void ExplicitRangeAddRemove() { string test; using (BPlusTree <int, string> data = Create(Options)) { data.Add(2, "v2"); data.Add(1, "v1"); int i = 0; for (; i < 8; i++) { data.TryAdd(i, "v" + i); } for (i = 16; i >= 8; i--) { data.TryAdd(i, "v" + i); } data.TryAdd(13, "v" + i); for (i = 0; i <= 16; i++) { if (!data.TryGetValue(i, out test)) { throw new ApplicationException(); } Assert.AreEqual("v" + i, test); } data.Remove(1); data.Remove(3); IEnumerator <KeyValuePair <int, string> > e = data.GetEnumerator(); Assert.IsTrue(e.MoveNext()); Assert.AreEqual(0, e.Current.Key); data.Add(1, "v1"); Assert.IsTrue(e.MoveNext()); data.Add(3, "v3"); Assert.IsTrue(e.MoveNext()); data.Remove(8); Assert.IsTrue(e.MoveNext()); e.Dispose(); data.Add(8, "v8"); i = 0; foreach (KeyValuePair <int, string> pair in data) { Assert.AreEqual(pair.Key, i++); } for (i = 0; i <= 16; i++) { Assert.IsTrue(data.Remove(i) && data.TryAdd(i, "v" + i)); } for (i = 6; i <= 12; i++) { Assert.IsTrue(data.Remove(i)); } for (i = 6; i <= 12; i++) { Assert.IsFalse(data.TryGetValue(i, out test)); Assert.IsNull(test); } for (i = 0; i <= 5; i++) { Assert.IsTrue(data.TryGetValue(i, out test)); Assert.AreEqual("v" + i, test); } for (i = 13; i <= 16; i++) { Assert.IsTrue(data.TryGetValue(i, out test)); Assert.AreEqual("v" + i, test); } for (i = 0; i <= 16; i++) { Assert.AreEqual(i < 6 || i > 12, data.Remove(i)); } } }
void SequencedTest(int start, int incr, int stop, string name) { int count = Math.Abs(start - stop)/Math.Abs(incr); const string myTestValue1 = "T1", myTestValue2 = "t2"; string test; using (BPlusTree<int, string> data = new BPlusTree<int, string>(Options)) { Stopwatch time = new Stopwatch(); time.Start(); //large order-forward for (int i = start; i != stop; i += incr) if (!data.TryAdd(i, myTestValue1)) throw new ApplicationException(); Trace.TraceInformation("{0} insert {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) if (!data.TryGetValue(i, out test) || test != myTestValue1) throw new ApplicationException(); Trace.TraceInformation("{0} seek {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) if (!data.TryUpdate(i, myTestValue2)) throw new ApplicationException(); Trace.TraceInformation("{0} modify {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) if (!data.TryGetValue(i, out test) || test != myTestValue2) throw new ApplicationException(); Trace.TraceInformation("{0} seek#2 {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); int tmpCount = 0; foreach (KeyValuePair<int, string> tmp in data) if (tmp.Value != myTestValue2) throw new ApplicationException(); else tmpCount++; if (tmpCount != count) throw new ApplicationException(); Trace.TraceInformation("{0} foreach {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) if (!data.Remove(i)) throw new ApplicationException(); Trace.TraceInformation("{0} delete {1} in {2}", name, count, time.ElapsedMilliseconds); for (int i = start; i != stop; i += incr) if (data.TryGetValue(i, out test)) throw new ApplicationException(); } }
void SequencedTest(int start, int incr, int stop, string name) { int count = Math.Abs(start - stop) / Math.Abs(incr); const string myTestValue1 = "T1", myTestValue2 = "t2"; string test; using (BPlusTree <int, string> data = new BPlusTree <int, string>(Options)) { Stopwatch time = new Stopwatch(); time.Start(); //large order-forward for (int i = start; i != stop; i += incr) { if (!data.TryAdd(i, myTestValue1)) { throw new ApplicationException(); } } Trace.TraceInformation("{0} insert {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) { if (!data.TryGetValue(i, out test) || test != myTestValue1) { throw new ApplicationException(); } } Trace.TraceInformation("{0} seek {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) { if (!data.TryUpdate(i, myTestValue2)) { throw new ApplicationException(); } } Trace.TraceInformation("{0} modify {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) { if (!data.TryGetValue(i, out test) || test != myTestValue2) { throw new ApplicationException(); } } Trace.TraceInformation("{0} seek#2 {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); int tmpCount = 0; foreach (KeyValuePair <int, string> tmp in data) { if (tmp.Value != myTestValue2) { throw new ApplicationException(); } else { tmpCount++; } } if (tmpCount != count) { throw new ApplicationException(); } Trace.TraceInformation("{0} foreach {1} in {2}", name, count, time.ElapsedMilliseconds); time.Reset(); time.Start(); for (int i = start; i != stop; i += incr) { if (!data.Remove(i)) { throw new ApplicationException(); } } Trace.TraceInformation("{0} delete {1} in {2}", name, count, time.ElapsedMilliseconds); for (int i = start; i != stop; i += incr) { if (data.TryGetValue(i, out test)) { throw new ApplicationException(); } } } }
public void TestRecoverCorruptedFile() { BPlusTree <int, string> .Options options = (BPlusTree <int, string> .Options)Options; options.BTreeOrder = 4; options.FileBlockSize = 512; options.FileGrowthRate = 25; options.ConcurrentWriters = 4; options.FileOpenOptions = FileOptions.None; using (BPlusTree <int, string> tree = new BPlusTree <int, string>(options)) { for (int i = 0; i < 100; i++) { Assert.IsTrue(tree.TryAdd(i, i.ToString())); } } using (Stream io = TempFile.Open()) { //first we can corrupt the root node, which is always at an offset of BlockSize io.Seek(512, SeekOrigin.Begin); io.Write(new byte[512], 0, 512); //Now let's corrupt one byte from the end of the node at index 3 io.Seek(1024 + 16, SeekOrigin.Begin); int len = PrimitiveSerializer.Int32.ReadFrom(io); io.Seek(1024 + 32 + len - 1, SeekOrigin.Begin); //secrets of fragmented file revealed... ugly i know. io.WriteByte(255); //overwrite last used byte in chunk. } options.CreateFile = CreatePolicy.Never; //Now that we've corrupted part of the file content, let's take a peek try { using (BPlusTree <int, string> tree = new BPlusTree <int, string>(options)) { foreach (KeyValuePair <int, string> kv in tree) { Assert.AreEqual(kv.Key.ToString(), kv.Value); } } Assert.Fail("Expected InvalidDataException"); } catch (InvalidDataException) { } Dictionary <int, string> found = new Dictionary <int, string>(); List <int> duplicates = new List <int>(); foreach (KeyValuePair <int, string> kv in BPlusTree <int, string> .RecoveryScan(options, FileShare.None)) { if (!found.ContainsKey(kv.Key)) { found.Add(kv.Key, kv.Value); } else { duplicates.Add(kv.Key); } Assert.AreEqual(kv.Key.ToString(), kv.Value); } Assert.AreNotEqual(0, found.Count); //The following may change... Assert.AreEqual(99, found.Count); Assert.IsFalse(found.ContainsKey(3), "should be missing #3"); Assert.AreEqual(0, duplicates.Count); }
private static void BasicTest() { BPlusTree <double, string> .OptionsV2 options = new BPlusTree <double, string> .OptionsV2(PrimitiveSerializer.Double, PrimitiveSerializer.String); options.CalcBTreeOrder(16, 24); options.CreateFile = CreatePolicy.Always; options.FileName = System.IO.Path.GetTempFileName(); using (var tree = new BPlusTree <double, string>(options)) { // Insertion to tree. // Note: numbers are NOT inserted sorted. tree.Add(30.1, "30.2"); tree.Add(10.1, "10.2"); tree.Add(20.1, "20.2"); tree.Add(80.1, "80.2"); tree.Add(40.1, "40.2"); tree.Add(60.1, "60.2"); tree.Add(70.1, "70.2"); tree.Add(50.1, "50.2"); // To get first element. // Since sorted, first element is: 10.1 KeyValuePair <double, string> first_with_Try; tree.TryGetFirst(out first_with_Try); // Similar to previous function. var first = tree.First(); // To get last element. // Since sorted, last element is: 80.1 KeyValuePair <double, string> last_with_Try; tree.TryGetLast(out last_with_Try); // Similar to previous function. var last = tree.Last(); // Given key get the value. // Key is valid, region.e., it is available in tree. // Hence it returns: "50.2" string value_of_valid_key; tree.TryGetValue(50.1, out value_of_valid_key); // Given key get the value. // Key is invalid, region.e., it is NOT available in tree. // Hence it returns: null (default value of int) string value_of_invalid_key; tree.TryGetValue(55, out value_of_invalid_key); // The "100" key is not available and no key is available greater than // that, hence .Current should return default value of key type (0 in this case). var key_not_available = tree.EnumerateFrom(100).GetEnumerator().Current; // Runtime error //var list = tree.ToList(); // Gets an enumerator. IEnumerator <KeyValuePair <double, string> > enumerator = tree.GetEnumerator(); // Iterating through items with enumerator. // starting from first item to last. while (enumerator.MoveNext()) { var item = enumerator.Current; } // Another syntac of iterations, which is automatically // calling "GetEnumerator" function. // starting from first item to last. foreach (var item in tree) { } // Iterates through items starting from given key: 40.1 (inclusively) // and goes till the last item. foreach (var item in tree.EnumerateFrom(39.1)) { } // Iterates through items starting from given index: 2 (inclusively) // and goes till the last item. foreach (var item in tree.EnumerateFrom(tree.ElementAtOrDefault(2).Key)) { } // Iterate from an item that is NOT available in collection // to the item which is neither available. foreach (var item in tree.EnumerateRange(20.5, 40.9)) { } // Gets the item at specific index. // All return valid values, but the last one which is // refereing to an index out-of-bound; the return of this // call is the default value for key and value. var element_at_0 = tree.ElementAtOrDefault(0); var element_at_1 = tree.ElementAtOrDefault(1); var element_at_2 = tree.ElementAtOrDefault(2); var element_at_3 = tree.ElementAtOrDefault(3); var element_at_100 = tree.ElementAtOrDefault(100); using (BPlusTree <double, string> data = new BPlusTree <double, string>(options)) { bool sT1 = data.TryAdd(1, "a"); bool sF1 = data.TryAdd(1, "a"); data[1] = "did it"; bool sT2 = data.TryUpdate(1, "a"); bool sT3 = data.TryUpdate(1, "c"); bool sT4 = data.TryUpdate(1, "d", "c"); bool sF2 = data.TryUpdate(1, "f", "c"); bool equality1 = "d".Equals(data[1]); bool sT5 = data.TryUpdate(1, "a", data[1]); bool equality2 = "a".Equals(data[1]); bool sF3 = data.TryUpdate(2, "b"); string val; bool st6 = data.TryRemove(1, out val) && val == "a"; bool sF4 = data.TryRemove(2, out val); bool notEqual = val.Equals("a"); } } }