public async Task RunAsync() { _logger.LogDebug("debug"); _logger.LogInformation("debug"); _logger.LogWarning("debug"); // this is just an example - practically, connecting the client // would be managed elsewhere - and the class would expect to // receive a connected client - and, that 'elsewhere' would also // dispose the client, etc. await _client.StartAsync(); await using var map = await _client.GetDictionaryAsync <string, int>("test-map"); await map.SetAsync("key", 42); var value = await map.GetAsync("key"); if (value != 42) { throw new Exception("Error!"); } Console.WriteLine("It worked."); // destroy the map await _client.DestroyAsync(map); }
private static async Task RunAsync(IHazelcastClient client, CancellationToken cancellationToken) { // 'await using' ensure that both the client and the map will be disposed before the method returns await using var c = client; await using var map = await client.GetDictionaryAsync <string, int>("test-map"); // loop while not canceled while (!cancellationToken.IsCancellationRequested) { // pretend to do some work var i = await map.GetAsync("foo"); i += 1; await map.SetAsync("foo", i); Console.WriteLine(i); try { await Task.Delay(1000, cancellationToken); } catch (OperationCanceledException) { // expected } } await client.DestroyAsync(map); }
public async Task Init() { _client = await CreateAndStartClientAsync(); var client = _client as HazelcastClient; Assert.That(client, Is.Not.Null); SerializationService = client.SerializationService; _dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString()); var nearCache = GetNearCache(_dictionary); Assert.That(nearCache, Is.InstanceOf <NearCaching.NearCache>()); }
/// <summary> /// Starts a new member and wait until it is added. /// </summary> /// <param name="rc">The remote controller.</param> /// <param name="client">The Hazelcast client.</param> /// <param name="cluster">The cluster.</param> /// <param name="expectedPartitionOwnersCount">The expected number of partition owners.</param> /// <returns>The new member.</returns> public static async Task <Member> StartMemberWaitAddedAsync(this IRemoteControllerClient rc, IHazelcastClient client, Cluster cluster, int expectedPartitionOwnersCount) { var clientInternal = (HazelcastClient)client; var added = new SemaphoreSlim(0); var partitions = new SemaphoreSlim(0); var subscriptionId = await clientInternal.SubscribeAsync(on => on .MemberAdded((sender, args) => { added.Release(); }) .PartitionsUpdated((sender, args) => { partitions.Release(); })) .CAF(); var member = await rc.StartMemberAsync(cluster).CAF(); await added.WaitAsync(TimeSpan.FromSeconds(120)).CAF(); // trigger the partition table creation var map = await client.GetDictionaryAsync <object, object>("default").CAF(); _ = map.GetAsync(new object()); await partitions.WaitAsync(TimeSpan.FromSeconds(120)).CAF(); await clientInternal.UnsubscribeAsync(subscriptionId).CAF(); var partitioner = clientInternal.Cluster.Partitioner; var partitionsCount = partitioner.Count; var owners = new HashSet <Guid>(); for (var i = 0; i < partitionsCount; i++) { var owner = partitioner.GetPartitionOwner(i); if (owner != default) { owners.Add(owner); } } Assert.AreEqual(expectedPartitionOwnersCount, owners.Count); return(member); }
public async Task NearCacheClearedBySet(bool strict) { var dictionary = await _client.GetDictionaryAsync <string, string>(_name); await using var _ = new AsyncDisposable(() => dictionary?.DestroyAsync() ?? default); var cache = GetNearCache(dictionary); // run test await RunTestInternal(dictionary); // if not strict, take plenty of time to become consistent if (!strict) { await Task.Delay(10_000); } var lastValue = _valuePut; var valueStr = await dictionary.GetAsync(Key); Assert.That(valueStr, Is.Not.Null); var valueInt = int.Parse(valueStr); // fail if not eventually consistent string msg = null; if (valueInt < lastValue) { msg = $"Err: getting {valueInt} instead of {lastValue}"; // flush Near Cache and re-fetch value cache.Clear(); valueStr = await dictionary.GetAsync(Key); Assert.That(valueStr, Is.Not.Null); valueInt = int.Parse(valueStr); // test again if (valueInt < lastValue) { msg += $" (flushing the cache the did not fix the inconsistency, getting {valueInt})."; } else { msg += " (flushing the cache did fix the inconsistency)."; } } Logger.LogInformation($"Statistics: \n\tHits: {cache.Statistics.Hits}\n\tMisses: {cache.Statistics.Misses}\n\tStale: {cache.Statistics.StaleReads}\n\tEvict: {cache.Statistics.Evictions}"); // fail after stopping hazelcast instance if (msg != null) { Logger.LogWarning(msg); Assert.Fail(msg); } // fail if strict is required and assertion was violated if (strict && _assertionViolationCount > 0) { msg = "Got " + _assertionViolationCount + " errors."; Logger.LogWarning(msg); Assert.Fail(msg); } }
public async Task NearCacheRecoversFromDistortions() { const string name = "nc-distortion"; const int size = 100000; var stop = false; // pre-populate the dictionary with (k,k) pairs for all keys Logger.LogInformation("Populate..."); Assert.True((await PopulateMapFromServerAsync(name, size)).Success); var dictionary = await _client.GetDictionaryAsync <int, int>(name); await using var _ = new AsyncDisposable(() => dictionary?.DestroyAsync() ?? default); var cache = GetNearCache(dictionary); Logger.LogInformation("Start tasks..."); var caching = Task.Run(async() => { while (!stop) { // reads values, thus populating the cache for (var i = 0; i < size && !stop; i++) { await dictionary.GetAsync(i); } } Logger.LogInformation("Caching stopped."); }); var distortingSequence = Task.Run(async() => { while (!stop) { // randomly changes the sequence of a partition on the server var response = await DistortRandomPartitionSequenceAsync(name); Assert.True(response.Success, response.Message); await Task.Delay(1000); } Logger.LogInformation("Distorting sequence stopped."); }); var distortingUuid = Task.Run(async() => { while (!stop) { // randomly changes the uuid of a partition on the server var response = await DistortRandomPartitionUuidAsync(); Assert.That(response.Success, response.Message); await Task.Delay(5000); } Logger.LogInformation("Distorting uuid stopped."); }); var addingOnMember = Task.Run(async() => { while (!stop) { // adds or update on the server var key = RandomProvider.Random.Next(size); var value = RandomProvider.Random.Next(int.MaxValue); var response = await PutOnMemberAsync(key, value, name); Assert.That(response.Success); await Task.Delay(100); } Logger.LogInformation("Adding stopped."); }); // let it run for 60 seconds Logger.LogInformation("Run..."); await Task.Delay(60_000); // stop Logger.LogInformation("Stop tasks..."); stop = true; await Task.WhenAll(caching, distortingSequence, distortingUuid, addingOnMember); Logger.LogInformation("Assert..."); await AssertEx.SucceedsEventually(async() => { // compare the values directly obtained from the server, // with the values obtained from the client via the cache, // everything should match var memberValues = await GetAllValueFromMemberAsync(size, name); for (var i = 0; i < size; i++) { var memberValue = memberValues[i] as int?; var clientValue = await dictionary.GetAsync(i); Assert.AreEqual(memberValue, clientValue, $"Bad value (i={i}, server={memberValue}, client={clientValue})"); } }, 40_000, 500); }
public async Task NearCacheTracksRemoteChanges() { var dictionary = await _client.GetDictionaryAsync <int, int>(_name); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); var tasks = new List <Task>(); var stop = false; const int entryCount = 10; const int writerTaskCount = 1; const int readerTaskCount = 10; // start tasks that add / update (thus invalidate) values on the server for (var i = 0; i < writerTaskCount; i++) { tasks.Add(Task.Run(async() => { while (!stop) { Assert.That((await PopulateMapWithRandomValueFromServerAsync(_name, entryCount)).Success); await Task.Delay(100); } })); } // start tasks that read values for (var i = 0; i < readerTaskCount; i++) { tasks.Add(Task.Run(async() => { while (!stop) { for (var j = 0; j < entryCount && !stop; j++) { await dictionary.GetAsync(j); } await Task.Delay(100); } })); } // run for some time await Task.Delay(8_000); // stop tasks stop = true; await Task.WhenAll(tasks); // assert that eventually all cache values will match what's on the member await AssertEx.SucceedsEventually(async() => { // 1. get all values, some should come from the cache var cacheValues = new List <int>(); for (var i = 0; i < entryCount; i++) { cacheValues.Add(await dictionary.GetAsync(i)); } // 2. get all values from server directly var memberValues = await GetAllValueFromMemberAsync(entryCount, _name); // after a while, all values in the cache will be same as server for (var i = 0; i < entryCount; i++) { Assert.AreEqual(memberValues[i], cacheValues[i]); } }, 10000, 500); }
public async Task TestNearCache() // CacheIsPopulatedByReads { var dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); // add values to the dictionary for (var i = 0; i < MaxSize; i++) { await dictionary.SetAsync("key" + i, "value" + i); } // near cache remains empty Assert.That(cache.Count, Is.EqualTo(0)); // get values, this will populate near cache var begin = DateTime.Now; for (var i = 0; i < MaxSize; i++) { await dictionary.GetAsync("key" + i); } var firstRead = DateTime.Now - begin; // get values again, this should read from near cache = be way faster // TODO: we should have a way (instrumentation) to count server requests begin = DateTime.Now; for (var i = 0; i < MaxSize; i++) { await dictionary.GetAsync("key" + i); } var secondRead = DateTime.Now - begin; // verify it's faster the second time Assert.IsTrue(secondRead < firstRead); // verify the cache contains all values Assert.That(cache.Count, Is.EqualTo(MaxSize)); Assert.That(cache.Statistics.EntryCount, Is.EqualTo(MaxSize)); }