Example #1
0
        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");
            }
        }
Example #5
0
 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);
        }
Example #13
0
        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");
                }
            }
        }