public void ClearTest() { var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", null), new KeyValuePair <string, object>("key b", null), new KeyValuePair <string, object>("key c", null), }); Assert.Throws <InvalidOperationException>(dict.Clear); Shield.InTransaction(() => { dict.Clear(); Assert.AreEqual(0, dict.Count); foreach (var kvp in dict) { Assert.Fail(); } }); Assert.AreEqual(0, dict.Count); Shield.InTransaction(() => { foreach (var kvp in dict) { Assert.Fail(); } }); }
public void EnumerationTest() { var ordinaryDict = new Dictionary <int, object>() { { 1, new object() }, { 101, new object() }, { 666999, new object() } }; var dict = new ShieldedDict <int, object>(ordinaryDict); var addedObject = new object(); // in preparation for the same changes done to dict inside transaction ordinaryDict.Add(2, addedObject); ordinaryDict.Remove(666999); Shield.InTransaction(() => { // as an IShielded implementor, the Dict is more complex and needs to be more carefully // tested for how well he manages thread-local data. So, we add some changes here. dict.Add(2, addedObject); dict.Remove(666999); int count = 0; var checkSet = new HashSet <int>(); foreach (var kvp in dict) { Assert.IsTrue(checkSet.Add(kvp.Key)); Assert.IsTrue(ordinaryDict.ContainsKey(kvp.Key)); Assert.AreEqual(ordinaryDict[kvp.Key], kvp.Value); count++; } Assert.AreEqual(3, count); }); }
public void ContainsTest() { var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", null), new KeyValuePair <string, object>("key b", null), new KeyValuePair <string, object>("key c", null), }); Assert.IsTrue(dict.ContainsKey("key a")); Assert.IsTrue(((ICollection <KeyValuePair <string, object> >)dict).Contains( new KeyValuePair <string, object>("key a", null))); Assert.IsFalse(dict.ContainsKey("not me")); Assert.IsFalse(((ICollection <KeyValuePair <string, object> >)dict).Contains( new KeyValuePair <string, object>("not me", null))); Shield.InTransaction(() => { dict.Add("new key", null); dict.Remove("key a"); Assert.IsFalse(dict.ContainsKey("key a")); Assert.IsFalse(((ICollection <KeyValuePair <string, object> >)dict).Contains( new KeyValuePair <string, object>("key a", null))); Assert.IsTrue(dict.ContainsKey("new key")); Assert.IsTrue(((ICollection <KeyValuePair <string, object> >)dict).Contains( new KeyValuePair <string, object>("new key", null))); }); }
public void RemoveTest() { var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", null), new KeyValuePair <string, object>("key b", null), new KeyValuePair <string, object>("key c", null), }); Assert.Throws <InvalidOperationException>(() => dict.Remove("key a")); Assert.Throws <InvalidOperationException>(() => ((ICollection <KeyValuePair <string, object> >)dict).Remove( new KeyValuePair <string, object>("key a", null))); Shield.InTransaction(() => { dict.Remove("key a"); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.ContainsKey("key a")); }); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.ContainsKey("key a")); Shield.InTransaction(() => { ((ICollection <KeyValuePair <string, object> >)dict).Remove( new KeyValuePair <string, object>("key b", null)); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.ContainsKey("key b")); }); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.ContainsKey("key b")); // ToList() avoids the need for a transaction, usually needed for enumerating collections. Assert.AreEqual("key c", dict.ToList().Single().Key); }
public void DictionaryRace() { var dict = new ShieldedDict <int, int>( Enumerable.Range(0, 100) .Select(i => new KeyValuePair <int, int>(i, 0)) .ToArray()); int transactionCount = 0; Task.WaitAll( Enumerable.Range(0, 1000).Select(i => Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); var a = dict[i % 100]; Thread.Sleep(5); dict[i % 100] = a + 1; }); }, TaskCreationOptions.LongRunning)).ToArray()); Shield.InTransaction(() => { var values = dict.Values; foreach (var value in values) { Assert.AreEqual(10, value); } }); Assert.Greater(transactionCount, 100); }
public void BasicTest() { var dict = new ShieldedDict<int, object>(); Assert.Throws<InvalidOperationException>(() => dict[1] = new object()); Shield.InTransaction(() => { dict[2] = new object(); // the TPL sometimes executes tasks on the same thread. object x1 = null; var t = new Thread(() => { Assert.IsFalse(Shield.IsInTransaction); Assert.IsFalse(dict.ContainsKey(2)); }); t.Start(); t.Join(); Assert.IsNotNull(dict[2]); }); object x2 = null; var t2 = new Thread(() => { x2 = dict[2]; }); t2.Start(); t2.Join(); Assert.IsNotNull(x2); Assert.IsNotNull(dict[2]); }
public void AddTest() { var dict = new ShieldedDict <int, object>(); Assert.Throws <InvalidOperationException>(() => dict.Add(1, new object())); Assert.Throws <InvalidOperationException>(() => ((ICollection <KeyValuePair <int, object> >)dict).Add( new KeyValuePair <int, object>(1, new object()))); var objectA = new object(); var objectB = new object(); Shield.InTransaction(() => { dict.Add(1, objectA); ((ICollection <KeyValuePair <int, object> >)dict).Add( new KeyValuePair <int, object>(2, objectB)); Assert.AreEqual(2, dict.Count); Assert.AreEqual(objectA, dict[1]); Assert.AreEqual(objectB, dict[2]); }); Assert.AreEqual(2, dict.Count); Assert.AreEqual(objectA, dict[1]); Assert.AreEqual(objectB, dict[2]); }
public void ConstructorAndIndexerTest() { var objectA = new object(); var objectB = new object(); var objectC = new object(); var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", objectA), new KeyValuePair <string, object>("key b", objectB), new KeyValuePair <string, object>("key c", objectC), }); Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectA, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.Throws <KeyNotFoundException>(() => { var x = dict["not me"]; }); Shield.InTransaction(() => Assert.Throws <KeyNotFoundException>(() => { var x = dict["not me"]; })); Shield.InTransaction(() => { dict["key a"] = objectC; Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectC, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); dict["key a"] = objectB; Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); }); Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); var objectD = new object(); Shield.InTransaction(() => { dict["a new one"] = objectD; Assert.AreEqual(4, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.AreEqual(objectD, dict["a new one"]); }); Assert.AreEqual(4, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.AreEqual(objectD, dict["a new one"]); }
private static void ReadItemsShielded(ShieldedDict<long, object> ld, int iterations) { var sp = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { object value; ld.TryGetValue(i, out value); } Console.WriteLine(sp.Elapsed + " Reading values Shielded dictionary"); }
public void ParallelOps() { var dict = new ShieldedDict <int, object>(); int transactionCount = 0; Task.WaitAll( Enumerable.Range(1, 100).Select(i => Task.Factory.StartNew(() => Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); dict[i] = new object(); Thread.Sleep(5); }), TaskCreationOptions.LongRunning)).ToArray()); Assert.AreEqual(100, transactionCount); }
public void SimpleRace() { var dict = new ShieldedDict <int, int>(); ParallelEnumerable.Range(0, 100000) .ForAll(i => Shield.InTransaction( () => dict[i % 100] = dict.ContainsKey(i % 100) ? dict[i % 100] + 1 : 1)); Shield.InTransaction(() => { for (int i = 0; i < 100; i++) { Assert.AreEqual(1000, dict[i]); } }); }
public void CopyToTest() { var dict = new ShieldedDict <int, object>( Enumerable.Range(1, 1000).Select(i => new KeyValuePair <int, object>(i, new object())).ToArray()); Assert.AreEqual(1000, dict.Count); var array = new KeyValuePair <int, object> [1100]; // this works out of transaction (and consequently, so do ToArray and ToList), by opening // a transaction itself. that could not be done when you do a foreach. ((ICollection <KeyValuePair <int, object> >)dict).CopyTo(array, 100); Assert.IsTrue(array.Skip(100).OrderBy(kvp => kvp.Key).SequenceEqual(dict.OrderBy(kvp => kvp.Key))); }
public void KeysAndValuesTest() { var objectA = new object(); var objectB = new object(); var objectC = new object(); var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", objectA), new KeyValuePair <string, object>("key b", objectB), new KeyValuePair <string, object>("key c", objectC), }); var hashKeys = new HashSet <string>(new string[] { "key a", "key b", "key c" }); var hashValues = new HashSet <object>(new object[] { objectA, objectB, objectC }); Assert.IsTrue(hashKeys.SetEquals(dict.Keys)); Assert.IsTrue(hashValues.SetEquals(dict.Values)); }
public void ParallelOps() { var dict = new ShieldedDict<int, object>(); int transactionCount = 0; Task.WaitAll( Enumerable.Range(1, 100).Select(i => Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); dict[i] = new object(); Thread.Sleep(5); }); }, TaskCreationOptions.LongRunning)).ToArray()); Assert.AreEqual(100, transactionCount); }
public void SetUpUnit() { Shield.InTransaction(() => { //init exposure store exposureStore = new ShieldedDict<string, Exposure>(); var e1 = Factory.NewShielded<Exposure>(); { e1.Client = "C1"; e1.Amount = 100; } var e2 = Factory.NewShielded<Exposure>(); { e2.Client = "C1"; e2.Amount = 200; } exposureStore["C1"] = e1; exposureStore["C2"] = e2; //init resa store resaStore = new ShieldedDict<Resa.Key, Resa>(); var d1 = Factory.NewShielded<Resa>(); { d1.DealId = "D1"; d1.Client = "C1"; d1.Amount = 10; } var d2 = Factory.NewShielded<Resa>(); { d2.DealId = "D2"; d2.Client = "C1"; d2.Amount = 40; } var d3 = Factory.NewShielded<Resa>(); { d3.DealId = "D3"; d3.Client = "C2"; d3.Amount = 60; } resaStore[d1.K] = d1; resaStore[d2.K] = d2; resaStore[d3.K] = d3; }); }
public void EqualityComparerTest() { var dict = new ShieldedDict <int, object>(new OddsAndEvens()); int retryCount = 0; Thread oneTime = null; Shield.InTransaction(() => { retryCount++; dict[1] = new object(); dict[2] = new object(); if (oneTime == null) { oneTime = new Thread(() => { Assert.IsFalse(Shield.IsInTransaction); Assert.IsFalse(dict.ContainsKey(2)); Assert.IsFalse(dict.ContainsKey(4)); Shield.InTransaction(() => dict[4] = new object()); }); oneTime.Start(); oneTime.Join(); } Assert.IsNotNull(dict[2]); Assert.IsNotNull(dict[4]); Assert.AreSame(dict[2], dict[4]); Assert.AreNotSame(dict[1], dict[2]); }); Assert.AreEqual(2, retryCount); object x2 = null; var t2 = new Thread(() => { x2 = dict[2]; Assert.AreSame(dict[2], dict[4]); Assert.AreNotSame(dict[1], dict[2]); }); t2.Start(); t2.Join(); Assert.IsNotNull(x2); Assert.IsNotNull(dict[2]); Assert.AreSame(dict[2], dict[4]); Assert.AreNotSame(dict[1], dict[2]); }
/// <summary> /// Constructor. /// </summary> /// <param name="ownId">The ID of this server.</param> /// <param name="serverIPs">The dictionary with server IDs and IP endpoints, including this server. Do not make later /// changes to any of the IPEndPoint objects!</param> public TcpTransport(string ownId, IDictionary <string, IPEndPoint> serverIPs) { OwnId = ownId ?? throw new ArgumentNullException(nameof(ownId)); if (serverIPs == null) { throw new ArgumentNullException(nameof(serverIPs)); } LocalEndpoint = serverIPs[ownId]; (ServerIPs, _clientConnections) = Shield.InTransaction(() => { var ips = new ShieldedDict <string, IPEndPoint>(serverIPs.Where(kvp => !StringComparer.InvariantCultureIgnoreCase.Equals(kvp.Key, ownId))); var clients = new ConcurrentDictionary <string, TcpClientConnection>( ips.Select(kvp => new KeyValuePair <string, TcpClientConnection>(kvp.Key, new TcpClientConnection(this, kvp.Value)))); Shield.PreCommit(() => ips.TryGetValue("any", out var _) || true, () => Shield.SyncSideEffect(UpdateClientConnections)); return(ips, clients); }); }
/// <summary> /// Creates n events, with three typical offers (1,X,2) for each. /// The events get IDs 1-n. /// </summary> public BetShop(int n) { PrepareFactory(); List <Event> initialEvents = new List <Event>(); Shield.InTransaction(() => { int eventIdGenerator = 1; int offerIdGenerator = 1; for (int i = 0; i < n; i++) { var newEvent = Factory.NewShielded <Event>(); newEvent.Id = eventIdGenerator++; newEvent.HomeTeam = "Home " + i; newEvent.AwayTeam = "Away " + i; initialEvents.Add(newEvent); var no = Factory.NewShielded <BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "1"; no.Odds = 2m; newEvent.BetOffers.Add(no); no = Factory.NewShielded <BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "X"; no.Odds = 4m; newEvent.BetOffers.Add(no); no = Factory.NewShielded <BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "2"; no.Odds = 4.5m; newEvent.BetOffers.Add(no); } }); Events = new ShieldedDict <int, Event>( initialEvents.Select(e => new KeyValuePair <int, Event>(e.Id, e)).ToArray()); }
public void DictionaryRace() { // a race over just one element var dict = new ShieldedDict<int, int>(); Shield.InTransaction(() => dict[1] = 0); int transactionCount = 0; Task.WaitAll( Enumerable.Repeat(1, 100).Select(i => Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); var a = dict[1]; Thread.Sleep(5); dict[1] = a + 1; }); }, TaskCreationOptions.LongRunning)).ToArray()); Assert.AreEqual(100, dict[1]); Assert.Greater(transactionCount, 100); }
public void TryGetValueTest() { var objectA = new object(); var dict = new ShieldedDict <string, object>(new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("key a", objectA), }); object x; Assert.IsTrue(dict.TryGetValue("key a", out x)); Assert.AreEqual(objectA, x); object y = null; Assert.IsTrue(Shield.InTransaction(() => dict.TryGetValue("key a", out y))); Assert.AreEqual(objectA, y); Assert.IsFalse(dict.TryGetValue("not me", out y)); Assert.IsFalse(Shield.InTransaction(() => dict.TryGetValue("not me", out y))); }
public void ClearTest() { var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", null), new KeyValuePair<string, object>("key b", null), new KeyValuePair<string, object>("key c", null), }); Assert.Throws<InvalidOperationException>(dict.Clear); Shield.InTransaction(() => { dict.Clear(); Assert.AreEqual(0, dict.Count); foreach (var kvp in dict) Assert.Fail(); }); Assert.AreEqual(0, dict.Count); Shield.InTransaction(() => { foreach (var kvp in dict) Assert.Fail(); }); }
public void BasicTest() { var dict = new ShieldedDict <int, object>(); Assert.Throws <InvalidOperationException>(() => dict[1] = new object()); bool detectable = false; using (Shield.WhenCommitting(dict, _ => detectable = true)) Shield.InTransaction(() => dict[1] = new object()); Assert.IsTrue(detectable); Shield.InTransaction(() => { dict[2] = new object(); // the TPL sometimes executes tasks on the same thread. var t = new Thread(() => { Assert.IsFalse(Shield.IsInTransaction); Assert.IsFalse(dict.ContainsKey(2)); }); t.Start(); t.Join(); Assert.IsNotNull(dict[2]); }); object x2 = null; var t2 = new Thread(() => { x2 = dict[2]; }); t2.Start(); t2.Join(); Assert.IsNotNull(x2); Assert.IsNotNull(dict[2]); }
public void DictionaryRace() { var dict = new ShieldedDict <int, int>( Enumerable.Range(0, 100) .Select(i => new KeyValuePair <int, int>(i, 0)) .ToArray()); int transactionCount = 0; Task.WaitAll( Enumerable.Range(0, 1000).Select(i => Task.Factory.StartNew(() => Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); var a = dict[i % 100]; Thread.Sleep(5); dict[i % 100] = a + 1; }), TaskCreationOptions.LongRunning)).ToArray()); Assert.IsTrue(dict.Values.SequenceEqual(Enumerable.Repeat(10, 100))); if (transactionCount == 100) { Assert.Inconclusive(); } }
public void EnumerationTest() { var ordinaryDict = new Dictionary <int, object>() { { 1, new object() }, { 101, new object() }, { 666999, new object() } }; var dict = new ShieldedDict <int, object>(ordinaryDict); var addedObject = new object(); // in preparation for the same changes done to dict inside transaction ordinaryDict.Add(2, addedObject); ordinaryDict.Remove(666999); Shield.InTransaction(() => { // as an IShielded implementor, the Dict is more complex and needs to be more carefully // tested for how well he manages thread-local data. So, we add some changes here. dict.Add(2, addedObject); dict.Remove(666999); Assert.IsTrue(dict.OrderBy(kvp => kvp.Key).SequenceEqual(ordinaryDict.OrderBy(kvp => kvp.Key))); }); }
public void AddTest() { var dict = new ShieldedDict<int, object>(); Assert.Throws<InvalidOperationException>(() => dict.Add(1, new object())); Assert.Throws<InvalidOperationException>(() => ((ICollection<KeyValuePair<int, object>>)dict).Add( new KeyValuePair<int, object>(1, new object()))); var objectA = new object(); var objectB = new object(); Shield.InTransaction(() => { dict.Add(1, objectA); ((ICollection<KeyValuePair<int, object>>)dict).Add( new KeyValuePair<int, object>(2, objectB)); Assert.AreEqual(2, dict.Count); Assert.AreEqual(objectA, dict[1]); Assert.AreEqual(objectB, dict[2]); }); Assert.AreEqual(2, dict.Count); Assert.AreEqual(objectA, dict[1]); Assert.AreEqual(objectB, dict[2]); }
/// <summary> /// Creates n events, with three typical offers (1,X,2) for each. /// The events get IDs 1-n. /// </summary> public BetShop(int n) { List<Shielded<Event>> initialEvents = new List<Shielded<Event>>(); Shield.InTransaction(() => { int eventIdGenerator = 1; int offerIdGenerator = 1; for (int i = 0; i < n; i++) { var newEvent = new Shielded<Event>(new Event() { Id = eventIdGenerator++, HomeTeam = "Home " + i, AwayTeam = "Away " + i }); // we have to use Modify, because each offer needs a ref to the shielded // event, which we do not have before that shielded event is constructed. And, // after he is constructed, he can only be changed like this. newEvent.Modify((ref Event e) => e.BetOffers = new ShieldedSeq<Shielded<BetOffer>>( new Shielded<BetOffer>(new BetOffer() { Id = offerIdGenerator++, Event = newEvent, Pick = "1", Odds = 2m }), new Shielded<BetOffer>(new BetOffer() { Id = offerIdGenerator++, Event = newEvent, Pick = "X", Odds = 4m }), new Shielded<BetOffer>(new BetOffer() { Id = offerIdGenerator++, Event = newEvent, Pick = "2", Odds = 4.5m }))); initialEvents.Add(newEvent); } }); Events = new ShieldedDict<int, Shielded<Event>>( initialEvents.Select(e => new KeyValuePair<int, Shielded<Event>>(e.Read.Id, e))); }
/// <summary> /// Creates n events, with three typical offers (1,X,2) for each. /// The events get IDs 1-n. /// </summary> public BetShop(int n) { PrepareFactory(); List<Event> initialEvents = new List<Event>(); Shield.InTransaction(() => { int eventIdGenerator = 1; int offerIdGenerator = 1; for (int i = 0; i < n; i++) { var newEvent = Factory.NewShielded<Event>(); newEvent.Id = eventIdGenerator++; newEvent.HomeTeam = "Home " + i; newEvent.AwayTeam = "Away " + i; initialEvents.Add(newEvent); var no = Factory.NewShielded<BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "1"; no.Odds = 2m; newEvent.BetOffers.Add(no); no = Factory.NewShielded<BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "X"; no.Odds = 4m; newEvent.BetOffers.Add(no); no = Factory.NewShielded<BetOffer>(); no.Id = offerIdGenerator++; no.Event = newEvent; no.Pick = "2"; no.Odds = 4.5m; newEvent.BetOffers.Add(no); } }); Events = new ShieldedDict<int, Event>( initialEvents.Select(e => new KeyValuePair<int, Event>(e.Id, e)).ToArray()); }
private static ShieldedDict<long, object> ShieldedDicAdd(int iterations) { var tmp = new ShieldedDict<long, object>(); var sp = Stopwatch.StartNew(); var rnd = new Random(32); for (int i = 0; i < iterations; i++) { Shield.InTransaction(() => { foreach (var item in Enumerable.Range(rnd.Next(0, i), Math.Max(i * 2, 16))) { tmp[item] = null; } }); } Console.WriteLine(sp.Elapsed + " Adding items, Shielded dictionary"); return tmp; }
public void TryGetValueTest() { var objectA = new object(); var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", objectA), }); object x; Assert.IsTrue(dict.TryGetValue("key a", out x)); Assert.AreEqual(objectA, x); object y = null; Assert.IsTrue(Shield.InTransaction(() => dict.TryGetValue("key a", out y))); Assert.AreEqual(objectA, y); Assert.IsFalse(dict.TryGetValue("not me", out y)); Assert.IsFalse(Shield.InTransaction(() => dict.TryGetValue("not me", out y))); }
public void DictionaryAccessExpandingTest() { var d = new ShieldedDict <int, object>(); // various combinations - one key is either written or just read, and the // WhenCommitting sub tries to mess with another key, or to promote the // read key. Shield.InTransaction(() => { d[1] = new object(); d[2] = new object(); }); // WhenCommitting does not fire unless at least something changed, so we need this Shielded <int> x = new Shielded <int>(); // reader promotion to writer not allowed using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[2]; })); } // new read not allowed using (Shield.WhenCommitting(fs => { var obj = d[2]; })) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[1]; })); } // new write not allowed using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[1]; })); } // same checks, but in situations when we did a write in the dict using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { d[1] = new object(); var obj = d[2]; })); } using (Shield.WhenCommitting(fs => { var obj = d[2]; })) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { d[1] = new object(); })); } using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws <AggregateException>(() => Shield.InTransaction(() => { d[1] = new object(); })); } // removing should likewise be restricted using (Shield.WhenCommitting(fs => { d.Remove(1); Assert.Throws <InvalidOperationException>( () => d.Remove(2)); })) { Shield.InTransaction(() => { d[1] = new object(); }); } // the exception was caught, and the WhenCommiting delegate committed Assert.IsFalse(d.ContainsKey(1)); Shield.InTransaction(() => d[1] = new object()); // finally, something allowed - reading from read or written, and writing into written using (Shield.WhenCommitting(fs => { var obj = d[1]; var obj2 = d[2]; d[2] = new object(); })) { Shield.InTransaction(() => { var obj = d[1]; d[2] = new object(); }); } }
public void RemoveTest() { var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", null), new KeyValuePair<string, object>("key b", null), new KeyValuePair<string, object>("key c", null), }); Assert.Throws<InvalidOperationException>(() => dict.Remove("key a")); Assert.Throws<InvalidOperationException>(() => ((ICollection<KeyValuePair<string, object>>)dict).Remove( new KeyValuePair<string, object>("key a", null))); Shield.InTransaction(() => { dict.Remove("key a"); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.ContainsKey("key a")); }); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.ContainsKey("key a")); Shield.InTransaction(() => { ((ICollection<KeyValuePair<string, object>>)dict).Remove( new KeyValuePair<string, object>("key b", null)); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.ContainsKey("key b")); }); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.ContainsKey("key b")); // ToList() avoids the need for a transaction, usually needed for enumerating collections. Assert.AreEqual("key c", dict.ToList().Single().Key); }
public void SimpleRace() { var dict = new ShieldedDict<int, int>(); ParallelEnumerable.Range(0, 100000) .ForAll(i => Shield.InTransaction( () => dict[i % 100] = dict.ContainsKey(i % 100) ? dict[i % 100] + 1 : 1)); Shield.InTransaction(() => { for (int i = 0; i < 100; i++) Assert.AreEqual(1000, dict[i]); }); }
public void EnumerationTest() { var ordinaryDict = new Dictionary<int, object>() { { 1, new object() }, { 101, new object() }, { 666999, new object() } }; var dict = new ShieldedDict<int, object>(ordinaryDict); var addedObject = new object(); // in preparation for the same changes done to dict inside transaction ordinaryDict.Add(2, addedObject); ordinaryDict.Remove(666999); Shield.InTransaction(() => { // as an IShielded implementor, the Dict is more complex and needs to be more carefully // tested for how well he manages thread-local data. So, we add some changes here. dict.Add(2, addedObject); dict.Remove(666999); int count = 0; var checkSet = new HashSet<int>(); foreach (var kvp in dict) { Assert.IsTrue(checkSet.Add(kvp.Key)); Assert.IsTrue(ordinaryDict.ContainsKey(kvp.Key)); Assert.AreEqual(ordinaryDict[kvp.Key], kvp.Value); count++; } Assert.AreEqual(3, count); }); }
public void KeysAndValuesTest() { var objectA = new object(); var objectB = new object(); var objectC = new object(); var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", objectA), new KeyValuePair<string, object>("key b", objectB), new KeyValuePair<string, object>("key c", objectC), }); var hashKeys = new HashSet<string>(new string[] { "key a", "key b", "key c" }); var hashValues = new HashSet<object>(new object[] { objectA, objectB, objectC }); Assert.IsTrue(hashKeys.SetEquals(dict.Keys)); Assert.IsTrue(hashValues.SetEquals(dict.Values)); }
public void DictionaryAccessExpandingTest() { var d = new ShieldedDict<int, object>(); // various combinations - one key is either written or just read, and the // WhenCommitting sub tries to mess with another key, or to promote the // read key. Shield.InTransaction(() => { d[1] = new object(); d[2] = new object(); }); // WhenCommitting does not fire unless at least something changed, so we need this Shielded<int> x = new Shielded<int>(); // reader promotion to writer not allowed using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[2]; })); } // new read not allowed using (Shield.WhenCommitting(fs => { var obj = d[2]; })) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[1]; })); } // new write not allowed using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { x.Value = 1; var obj = d[1]; })); } // same checks, but in situations when we did a write in the dict using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { d[1] = new object(); var obj = d[2]; })); } using (Shield.WhenCommitting(fs => { var obj = d[2]; })) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { d[1] = new object(); })); } using (Shield.WhenCommitting(fs => d[2] = new object())) { Assert.Throws<InvalidOperationException>(() => Shield.InTransaction(() => { d[1] = new object(); })); } // removing should likewise be restricted using (Shield.WhenCommitting(fs => { d.Remove(1); Assert.Throws<InvalidOperationException>( () => d.Remove(2)); })) { Shield.InTransaction(() => { d[1] = new object(); }); } // the exception was caught, and the WhenCommiting delegate committed Assert.IsFalse(d.ContainsKey(1)); Shield.InTransaction(() => d[1] = new object()); // finally, something allowed - reading from read or written, and writing into written using (Shield.WhenCommitting(fs => { var obj = d[1]; var obj2 = d[2]; d[2] = new object(); })) { Shield.InTransaction(() => { var obj = d[1]; d[2] = new object(); }); } }
private static void DictionaryTest() { ShieldedDict<int, Shielded<int>> dict = new ShieldedDict<int, Shielded<int>>(); var randomizr = new Random(); foreach (var _ in Enumerable.Repeat(0, 10)) { var transactionCounter = 0; var time = mtTest("dictionary", 10000, i => { var rnd = randomizr.Next(10); if (i % 2 == 0) // adder task - 500 of these return Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCounter); var v = dict.ContainsKey(rnd) ? dict[rnd] : null; int? num = v != null ? (int?)v.Read : null; Thread.Sleep(1); if (v == null) dict[rnd] = new Shielded<int>(1); else if (v.Read == -1) dict.Remove(rnd); else v.Modify((ref int a) => a = num.Value + 1); } ); }, TaskCreationOptions.LongRunning ); else // subtractor task - 500 of these return Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCounter); var v = dict.ContainsKey(rnd) ? dict[rnd] : null; int? num = v != null ? (int?)v.Read : null; Thread.Sleep(1); if (v == null) dict[rnd] = new Shielded<int>(-1); else if (v.Read == 1) dict.Remove(rnd); else v.Modify((ref int a) => a = num.Value - 1); } ); }, TaskCreationOptions.LongRunning ); }); var sum = Enumerable.Range(0, 10).Sum(n => dict.ContainsKey(n) ? dict[n] : 0); Console.WriteLine(" {0} ms with {1} iterations and sum {2}.", time, transactionCounter, sum); } }
public static void TreePoolTest() { int numThreads = 4; int numItems = 200000; // for some reason, if this is replaced with ShieldedDict, KeyAlreadyPresent // exception is thrown. under one key you can then find an entity which does // not have that key. complete mystery. var tree = new ShieldedDict<Guid, TreeItem>(); var barrier = new Barrier(numThreads + 1); int reportEvery = 10000; Shielded<int> lastReport = new Shielded<int>(0); Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow); Shield.Conditional(() => tree.Count >= lastReport + reportEvery, () => { DateTime newNow = DateTime.UtcNow; int count = tree.Count; int speed = (count - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds; lastTime.Assign(newNow); lastReport.Modify((ref int n) => n += reportEvery); Shield.SideEffect(() => { Console.Write("\n{0} at {1} item/s", count, speed); }); return true; }); TreeItem x = new TreeItem(); _timer = new Stopwatch(); _timer.Start(); var time = _timer.ElapsedMilliseconds; foreach (var k in Enumerable.Repeat(1, numItems)) Shield.InTransaction(() => x.Id); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("1 read transactions in {0} ms.", time); var bags = new List<Action>[numThreads]; var threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { var bag = bags[i] = new List<Action>(); threads[i] = new Thread(() => { foreach (var a in bag) { try { a(); } catch { Console.Write(" * "); } } barrier.SignalAndWait(); }); } foreach (var i in Enumerable.Range(0, numItems)) { var item1 = new TreeItem(); bags[i % numThreads].Add(() => Shield.InTransaction(() => { tree.Add(item1.Id, item1); })); } for (int i = 0; i < numThreads; i++) threads[i].Start(); barrier.SignalAndWait(); time = _timer.ElapsedMilliseconds; Console.WriteLine(" {0} ms.", time); Console.WriteLine("\nReading sequentially..."); time = _timer.ElapsedMilliseconds; var keys = Shield.InTransaction(() => tree.Keys); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("Keys read in {0} ms.", time); time = _timer.ElapsedMilliseconds; Shield.InTransaction(() => { foreach (var kvp in tree) x = kvp.Value; }); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("Items read by enumerator in {0} ms.", time); time = _timer.ElapsedMilliseconds; Shield.InTransaction(() => { foreach (var k in keys) x = tree[k]; }); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("Items read by key in one trans in {0} ms.", time); time = _timer.ElapsedMilliseconds; foreach (var k in keys) x = tree[k]; time = _timer.ElapsedMilliseconds - time; Console.WriteLine("Items read by key separately in {0} ms.", time); time = _timer.ElapsedMilliseconds; keys.AsParallel().ForAll(k => x = tree[k]); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("Items read by key in parallel in {0} ms.", time); time = _timer.ElapsedMilliseconds; foreach (var k in Enumerable.Repeat(1, numItems)) Shield.InTransaction(() => x.Id); time = _timer.ElapsedMilliseconds - time; Console.WriteLine("1 read transactions in {0} ms.", time); }
public void ContainsTest() { var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", null), new KeyValuePair<string, object>("key b", null), new KeyValuePair<string, object>("key c", null), }); Assert.IsTrue(dict.ContainsKey("key a")); Assert.IsTrue(((ICollection<KeyValuePair<string, object>>)dict).Contains( new KeyValuePair<string, object>("key a", null))); Assert.IsFalse(dict.ContainsKey("not me")); Assert.IsFalse(((ICollection<KeyValuePair<string, object>>)dict).Contains( new KeyValuePair<string, object>("not me", null))); Shield.InTransaction(() => { dict.Add("new key", null); dict.Remove("key a"); Assert.IsFalse(dict.ContainsKey("key a")); Assert.IsFalse(((ICollection<KeyValuePair<string, object>>)dict).Contains( new KeyValuePair<string, object>("key a", null))); Assert.IsTrue(dict.ContainsKey("new key")); Assert.IsTrue(((ICollection<KeyValuePair<string, object>>)dict).Contains( new KeyValuePair<string, object>("new key", null))); }); }
public void ConstructorAndIndexerTest() { var objectA = new object(); var objectB = new object(); var objectC = new object(); var dict = new ShieldedDict<string, object>(new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("key a", objectA), new KeyValuePair<string, object>("key b", objectB), new KeyValuePair<string, object>("key c", objectC), }); Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectA, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.Throws<KeyNotFoundException>(() => { var x = dict["not me"]; }); Shield.InTransaction(() => Assert.Throws<KeyNotFoundException>(() => { var x = dict["not me"]; })); Shield.InTransaction(() => { dict["key a"] = objectC; Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectC, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); dict["key a"] = objectB; Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); }); Assert.AreEqual(3, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); var objectD = new object(); Shield.InTransaction(() => { dict["a new one"] = objectD; Assert.AreEqual(4, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.AreEqual(objectD, dict["a new one"]); }); Assert.AreEqual(4, dict.Count); Assert.AreEqual(objectB, dict["key a"]); Assert.AreEqual(objectB, dict["key b"]); Assert.AreEqual(objectC, dict["key c"]); Assert.AreEqual(objectD, dict["a new one"]); }
public static void TreeTest() { int numTasks = 100000; int reportEvery = 1000; ShieldedTree<Guid, TreeItem> tree = new ShieldedTree<Guid, TreeItem>(); int transactionCount = 0; Shielded<int> lastReport = new Shielded<int>(0); Shielded<int> countComplete = new Shielded<int>(0); // Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow); // // Shield.Conditional(() => countComplete >= lastReport + reportEvery, () => // { // DateTime newNow = DateTime.UtcNow; // int speed = (countComplete - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds; // lastTime.Assign(newNow); // lastReport.Modify((ref int n) => n += reportEvery); // int count = countComplete; // Shield.SideEffect(() => // { // Console.Write("\n{0} at {1} item/s", count, speed); // } // ); // return true; // } // ); if (true) { var treeTime = mtTest("tree", numTasks, i => { return Task.Factory.StartNew(() => { var item1 = new TreeItem(); Shield.InTransaction(() => { //Interlocked.Increment(ref transactionCount); tree.Add(item1.Id, item1); // countComplete.Commute((ref int c) => c++); } ); } ); } ); Guid? previous = null; bool correct = true; Shield.InTransaction(() => { int count = 0; foreach (var item in tree) { count++; if (previous != null && previous.Value.CompareTo(item.Key) > 0) { correct = false; break; } previous = item.Key; } correct = correct && (count == numTasks); } ); Console.WriteLine("\n -- {0} ms with {1} iterations and is {2}.", treeTime, transactionCount, correct ? "correct" : "incorrect"); } if (true) { ShieldedDict<Guid, TreeItem> dict = new ShieldedDict<Guid, TreeItem>(); transactionCount = 0; Shield.InTransaction(() => { countComplete.Assign(0); lastReport.Assign(0); } ); var time = mtTest("dictionary", numTasks, i => { return Task.Factory.StartNew(() => { var item1 = new TreeItem(); Shield.InTransaction(() => { //Interlocked.Increment(ref transactionCount); dict[item1.Id] = item1; // countComplete.Commute((ref int c) => c++); } ); } ); } ); Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.", time, transactionCount); } if (true) { ConcurrentDictionary<Guid, TreeItem> dict = new ConcurrentDictionary<Guid, TreeItem>(); var time = mtTest("ConcurrentDictionary", numTasks, i => { return Task.Factory.StartNew(() => { var item1 = new TreeItem(); dict[item1.Id] = item1; } ); } ); Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.", time, numTasks); } }
public void CopyToTest() { var dict = new ShieldedDict<int, object>( Enumerable.Range(1, 1000).Select(i => new KeyValuePair<int, object>(i, new object())).ToArray()); Assert.AreEqual(1000, dict.Count); var array = new KeyValuePair<int, object>[1100]; // this works out of transaction (and consequently, so do ToArray and ToList), by opening // a transaction itself. that could not be done when you do a foreach. ((ICollection<KeyValuePair<int, object>>)dict).CopyTo(array, 100); var keys = new HashSet<int>(); foreach (var kvp in array.Skip(100)) { Assert.IsTrue(dict.ContainsKey(kvp.Key)); Assert.IsTrue(keys.Add(kvp.Key)); Assert.AreEqual(dict[kvp.Key], kvp.Value); } }
//private static SpinLock _spinLock = new SpinLock(SettingsService.Default.AppSwitchSettings.Read<bool>()); // SpinLockThrowsOnReenter public IsolatedSettingsStorage(IsolatedStorageScope scope) { _storage = IsolatedStorageFile.GetStore(scope, null); _settings = new ShieldedDict <string, object>(StringComparer.CurrentCulture); _disposed = false; }
public void DictionaryRace() { var dict = new ShieldedDict<int, int>( Enumerable.Range(0, 100) .Select(i => new KeyValuePair<int, int>(i, 0)) .ToArray()); int transactionCount = 0; Task.WaitAll( Enumerable.Range(0, 1000).Select(i => Task.Factory.StartNew(() => { Shield.InTransaction(() => { Interlocked.Increment(ref transactionCount); var a = dict[i % 100]; Thread.Sleep(5); dict[i % 100] = a + 1; }); }, TaskCreationOptions.LongRunning)).ToArray()); Shield.InTransaction(() => { var values = dict.Values; foreach (var value in values) Assert.AreEqual(10, value); }); Assert.Greater(transactionCount, 100); }