blob: ea77dc96809d2c52303b6f86028ed2829f4a4766 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ReSharper disable LoopVariableIsNeverChangedInsideLoop
namespace Apache.Ignite.Core.Tests.Cache.Platform
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Cache.Configuration;
using Apache.Ignite.Core.Cache.Eviction;
using Apache.Ignite.Core.Cache.Expiry;
using Apache.Ignite.Core.Cache.Query;
using Apache.Ignite.Core.Cache.Store;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Datastream;
using Apache.Ignite.Core.Events;
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.Log;
using Apache.Ignite.Core.Tests.Client.Cache;
using NUnit.Framework;
/// <summary>
/// Platform cache test.
/// </summary>
public sealed class PlatformCacheTest
{
/** */
private const string CacheName = "default";
/** */
private const int NearCacheMaxSize = 3;
/** */
private IIgnite _grid;
/** */
private IIgnite _grid2;
/** */
private IIgnite _client;
/** */
private ListLogger _logger;
/// <summary>
/// Fixture set up.
/// </summary>
[TestFixtureSetUp]
public void FixtureSetUp()
{
_logger = new ListLogger(new ConsoleLogger())
{
EnabledLevels = new[] {LogLevel.Error}
};
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
CacheConfiguration = new[]
{
new CacheConfiguration
{
NearConfiguration = new NearCacheConfiguration
{
EvictionPolicy = new FifoEvictionPolicy {MaxSize = NearCacheMaxSize},
},
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
Name = CacheName,
QueryEntities = new[]
{
new QueryEntity(typeof(Foo))
}
}
},
IgniteInstanceName = "server1",
Logger = _logger
};
_grid = Ignition.Start(cfg);
var cfg2 = new IgniteConfiguration(cfg)
{
IgniteInstanceName = "server2"
};
_grid2 = Ignition.Start(cfg2);
var clientCfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
ClientMode = true,
IgniteInstanceName = "client",
IncludedEventTypes = new[] {EventType.CacheEntryCreated}
};
_client = Ignition.Start(clientCfg);
WaitForRebalance();
}
/// <summary>
/// Fixture tear down.
/// </summary>
[TestFixtureTearDown]
public void FixtureTearDown()
{
Ignition.StopAll(true);
}
/// <summary>
/// Test tear down.
/// </summary>
[TearDown]
public void TearDown()
{
_grid.GetCache<int, int>(CacheName).RemoveAll();
_logger.Clear();
}
/// <summary>
/// Tests that platform cache does not return same instance that we Put there:
/// there is always serialize-deserialize roundtrip, except on primary nodes.
/// </summary>
[Test]
public void TestPlatformCachePutGetReturnsNewObject(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode,
[Values(true, false)] bool primaryKey)
{
var cache = GetCache<int, Foo>(mode);
var key = TestUtils.GetKey(_grid, cache.Name, primaryKey: primaryKey);
var obj = new Foo(key);
cache[key] = obj;
var res1 = cache[key];
var res2 = cache[key];
// Returned object is Equal to the initial.
Assert.AreEqual(obj, res1);
// But not the same - new instance is stored in platform cache,
// except primary on servers - thread-local optimization avoids extra deserialization there.
if (primaryKey && mode == CacheTestMode.ServerLocal || !primaryKey && mode == CacheTestMode.ServerRemote)
{
Assert.AreSame(obj, res1);
}
else
{
Assert.AreNotSame(obj, res1);
}
// Repeated Get call returns same instance from platform cache.
Assert.AreSame(res1, res2);
}
/// <summary>
/// Tests that platform cache returns the same object on every get.
/// </summary>
[Test]
public void TestPlatformCacheRepeatedGetReturnsSameObjectReference(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode,
[Values(true, false)] bool primaryKey,
[Values(true, false)] bool localPut)
{
var cache = GetCache<int, Foo>(mode);
var key = TestUtils.GetKey(_grid, cache.Name, primaryKey: primaryKey);
var obj = new Foo(3);
if (localPut)
{
// Local put through the same cache instance: obj is in platform cache directly.
cache[key] = obj;
}
else
{
// Put through remote node: platform cache is updated only on Get.
var remoteCache = GetCache<int, Foo>(
mode == CacheTestMode.Client ? CacheTestMode.ServerRemote : CacheTestMode.Client);
remoteCache[key] = obj;
}
Assert.AreEqual(3, cache[key].Bar);
Assert.AreSame(cache[key], cache[key]);
}
/// <summary>
/// Tests that platform cache returns the same object on every get.
/// </summary>
[Test]
public void TestPlatformCacheRepeatedRemoteGetReturnsSameObjectReference(
[Values(CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode,
[Values(true, false)] bool primaryKey)
{
var remoteCache = GetCache<int, Foo>(CacheTestMode.ServerLocal);
var localCache = GetCache<int, Foo>(mode);
var key = TestUtils.GetKey(_grid, remoteCache.Name, primaryKey: primaryKey);
remoteCache[key] = new Foo();
TestUtils.WaitForTrueCondition(() =>
{
Foo val;
return localCache.TryGet(key, out val) &&
ReferenceEquals(val, localCache.Get(key));
});
// Invalidate after get.
remoteCache[key] = new Foo(1);
TestUtils.WaitForTrueCondition(() =>
{
Foo val;
return localCache.TryGet(key, out val) &&
val.Bar == 1 &&
ReferenceEquals(val, localCache.Get(key));
});
}
/// <summary>
/// Tests that platform cache is updated from remote node after being populated with local Put call.
/// </summary>
[Test]
public void TestPlatformCacheUpdatesFromRemoteNode(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode1,
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode2)
{
var cache1 = GetCache<int, int>(mode1);
var cache2 = GetCache<int, int>(mode2);
cache1[1] = 1;
cache2[1] = 2;
Assert.True(TestUtils.WaitForCondition(() => cache1[1] == 2, 300));
}
/// <summary>
/// Tests that platform cache is updated from another cache instance after being populated with local Put call.
/// </summary>
[Test]
public void TestPlatformCacheUpdatesFromAnotherLocalInstance()
{
var cache1 = _grid.GetCache<int, int>(CacheName);
var cache2 = _grid.GetCache<int, int>(CacheName);
cache1[1] = 1;
cache2.Replace(1, 2);
Assert.True(TestUtils.WaitForCondition(() => cache1[1] == 2, 300));
}
/// <summary>
/// Tests that platform cache is cleared from remote node after being populated with local Put call.
/// </summary>
[Test]
public void TestPlatformCacheRemoveFromRemoteNodeAfterLocalPut()
{
var localCache = _client.GetOrCreateNearCache<int, int>(CacheName, new NearCacheConfiguration());
var remoteCache = _grid.GetCache<int, int>(CacheName);
localCache[1] = 1;
remoteCache.Remove(1);
int unused;
Assert.True(TestUtils.WaitForCondition(() => !localCache.TryGet(1, out unused), 300));
}
/// <summary>
/// Tests that primary keys are always up-to-date in platform cache.
/// </summary>
[Test]
public void TestPrimaryKeyOnServerNodeIsAddedToPlatformCacheAfterRemotePut()
{
var clientCache = _client.GetCache<int, int>(CacheName);
var serverCache = _grid.GetCache<int, int>(CacheName);
var key = TestUtils.GetPrimaryKey(_grid, CacheName);
clientCache[key] = 2;
Assert.AreEqual(2, serverCache.LocalPeek(key, CachePeekMode.Platform));
clientCache[key] = 3;
Assert.AreEqual(3, serverCache.LocalPeek(key, CachePeekMode.Platform));
var nonPrimaryNodeCache = _grid2.GetCache<int, int>(CacheName);
Assert.AreEqual(0, nonPrimaryNodeCache.GetLocalSize(CachePeekMode.Platform));
}
/// <summary>
/// Tests that same platform cache can be used with different sets of generic type parameters.
/// </summary>
[Test]
public void TestSamePlatformCacheWithDifferentGenericTypeParameters()
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var cache1 = _grid.CreateCache<int, int>(cfg);
var cache2 = _grid.GetCache<string, string>(cfg.Name);
var cache3 = _grid.GetCache<int, Foo>(cfg.Name);
var cache4 = _grid.GetCache<object, object>(cfg.Name);
cache1[1] = 1;
cache2["1"] = "1";
cache3[2] = new Foo(5);
Assert.AreEqual(cache4[1], 1);
Assert.AreEqual(cache4["1"], "1");
Assert.AreSame(cache4[2], cache3[2]);
}
/// <summary>
/// Tests that reference semantics is preserved on repeated get after generic parameters change.
/// </summary>
[Test]
public void TestRepeatedGetReturnsSameInstanceAfterGenericTypeParametersChange()
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var cache1 = _grid.CreateCache<int, Foo>(cfg);
cache1[1] = new Foo(42);
cache1[2] = new Foo(43);
// Use different type parameters.
var cache2 = _grid.GetCache<int, string>(cfg.Name);
cache2[1] = "x";
// Check that platform cache still works for old entries.
Assert.Throws<InvalidCastException>(() => cache1.Get(1));
Assert.AreEqual(43, cache1[2].Bar);
Assert.AreSame(cache1[2], cache1[2]);
}
/// <summary>
/// Tests that cache data is invalidated in the existing cache instance after generic parameters change.
/// </summary>
[Test]
public void TestDataInvalidationAfterGenericTypeParametersChange()
{
var cacheName = TestUtils.TestName;
var cfg = new CacheConfiguration
{
Name = cacheName,
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var cache = _client.CreateCache<int, int>(cfg, cfg.NearConfiguration);
cache[1] = 1;
var newCache = _client.GetOrCreateNearCache<int, object>(cacheName, cfg.NearConfiguration);
newCache[1] = 2;
Assert.AreEqual(2, cache[1]);
}
/// <summary>
/// Tests that error during Put does not affect correct data in platform cache.
/// </summary>
[Test]
public void TestFailedPutKeepsCorrectPlatformCacheValue(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
CacheStoreFactory = new FailingCacheStore(),
WriteThrough = true
};
var cache = GetIgnite(mode).CreateCache<int, Foo>(cfg, new NearCacheConfiguration(),
new PlatformCacheConfiguration());
// First write succeeds.
cache.Put(1, new Foo(1));
Assert.AreEqual(1, cache.LocalPeek(1, CachePeekMode.Platform).Bar);
// Special value causes write failure. Platform cache value is still correct.
Assert.Throws<CacheStoreException>(() => cache.Put(1, new Foo(FailingCacheStore.FailingValue)));
Assert.AreEqual(1, cache.LocalPeek(1, CachePeekMode.Platform).Bar);
}
/// <summary>
/// Tests that platform cache is updated/invalidated by SQL DML operations.
/// </summary>
[Test]
public void TestSqlUpdatesPlatformCache()
{
var cache = GetCache<int, Foo>(CacheTestMode.Client);
var value = new Foo(5);
cache[1] = value;
cache.Query(new SqlFieldsQuery("update Foo set Bar = 7 where Bar = 5"));
var res = cache[1];
Assert.AreEqual(7, res.Bar);
}
/// <summary>
/// Tests that eviction policy removes platform cache data for the key.
/// </summary>
[Test]
public void TestFifoEvictionPolicyRemovesPlatformCacheValue(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cache = GetCache<int, Foo>(mode);
TestEvictionPolicyRemovesPlatformCacheValue(mode, cache);
}
/// <summary>
/// Tests that eviction policy removes platform cache data for the key.
/// </summary>
[Test]
public void TestLruEvictionPolicyRemovesPlatformCacheValue(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cfg = new CacheConfiguration
{
Name = "lru-test-" + mode,
NearConfiguration = new NearCacheConfiguration
{
EvictionPolicy = new LruEvictionPolicy
{
MaxSize = NearCacheMaxSize,
BatchSize = 1
},
},
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var ignite = GetIgnite(mode);
var cache = ignite.CreateCache<int, Foo>(cfg, cfg.NearConfiguration);
TestEvictionPolicyRemovesPlatformCacheValue(mode, cache);
}
/// <summary>
/// Tests that last N added entries are in platform cache, where N is MaxSize.
/// </summary>
[Test]
public void TestEvictionPolicyKeepsLastEntriesInPlatformCache(
[Values(true, false)] bool lruOrFifo,
[Values(true, false)] bool getOrCreate)
{
const int maxSize = 30;
var serverCache = _grid.CreateCache<int, Foo>(TestUtils.TestName);
var nearCfg = new NearCacheConfiguration
{
EvictionPolicy = lruOrFifo
? (IEvictionPolicy) new LruEvictionPolicy
{
MaxSize = maxSize
}
: new FifoEvictionPolicy
{
MaxSize = maxSize
}
};
var platformCfg = new PlatformCacheConfiguration();
var clientCache = getOrCreate
? _client.GetOrCreateNearCache<int, Foo>(serverCache.Name, nearCfg, platformCfg)
: _client.CreateNearCache<int, Foo>(serverCache.Name, nearCfg, platformCfg);
var keys = Enumerable.Range(1, maxSize * 5).ToList();
var nearKeys = keys.AsEnumerable().Reverse().Take(maxSize).ToArray();
keys.ForEach(k => serverCache.Put(k, new Foo(k)));
// Get from client to populate platform cache.
clientCache.GetAll(nearKeys);
Assert.AreEqual(nearKeys.Length, clientCache.GetLocalSize(CachePeekMode.Platform));
// Check that Get returns instance from platform cache.
foreach (var key in nearKeys)
{
Assert.AreSame(clientCache.LocalPeek(key, CachePeekMode.Platform), clientCache.Get(key));
}
// Check that GetAll returns instances from platform cache.
var all = clientCache.GetAll(nearKeys);
foreach (var entry in all)
{
Assert.AreSame(clientCache.LocalPeek(entry.Key, CachePeekMode.Platform), entry.Value);
}
}
/// <summary>
/// Tests that evicted entry is reloaded from Java after update from another node.
/// Eviction on Java side for non-local entry (not a primary key for this node) disconnects near cache notifier.
/// This test verifies that eviction on Java side causes eviction on .NET side, and does not cause stale data.
/// </summary>
[Test]
public void TestCacheGetFromEvictedEntryAfterUpdateFromAnotherNode()
{
var cfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration
{
EvictionPolicy = new FifoEvictionPolicy
{
MaxSize = 1
}
},
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var serverCache = _grid.CreateCache<int, int>(cfg);
var clientCache = _client.GetOrCreateNearCache<int, int>(cfg.Name, cfg.NearConfiguration);
clientCache[1] = 1;
clientCache[2] = 2;
serverCache[1] = 11;
Assert.AreEqual(11, clientCache[1]);
}
/// <summary>
/// Tests that scan query uses platform cache to pass values to <see cref="ScanQuery{TK,TV}.Filter"/> when possible.
/// </summary>
[Test]
public void TestScanQueryFilterUsesValueFromPlatformCache(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cache = GetCache<int, Foo>(mode);
const int count = 100;
cache.PutAll(Enumerable.Range(1, count).Select(x => new KeyValuePair<int, Foo>(x, new Foo(x))));
// Filter will check that value comes from native platform cache.
var filter = new ScanQueryPlatformCacheFilter
{
CacheName = cache.Name
};
var res = cache.Query(new ScanQuery<int, Foo>(filter));
Assert.AreEqual(count, res.Count());
}
/// <summary>
/// Tests that scan query falls back to deserialized value from Java when platform cache value is missing.
/// </summary>
[Test]
public void TestScanQueryFilterUsesFallbackValueWhenNotInPlatformCache(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cache = GetCache<int, Foo>(mode);
const int count = 100;
var data = Enumerable.Range(1, count).ToDictionary(x=> x, x => new Foo(x));
cache.PutAll(data);
// Filter will check that value does not come from native platform cache.
var filter = new ScanQueryNoPlatformCacheFilter
{
CacheName = cache.Name
};
// Clear platform cache using internal API.
foreach (var ignite in Ignition.GetAll())
{
var platformCache = ((Ignite) ignite).PlatformCacheManager.TryGetPlatformCache(BinaryUtils.GetCacheId(cache.Name));
if (platformCache != null)
{
platformCache.Clear();
}
}
var res = cache.Query(new ScanQuery<int, Foo>(filter));
Assert.AreEqual(count, res.Count());
}
/// <summary>
/// Tests that local scan query uses platform cache directly, avoiding Java roundtrip.
/// </summary>
[Test]
public void TestLocalScanQueryUsesKeysAndValuesFromPlatformCache([Values(true, false)] bool withFilter,
[Values(true, false)] bool withPartition)
{
var cache = GetCache<int, Foo>(CacheTestMode.ServerLocal);
cache.PutAll(Enumerable.Range(1, 100).ToDictionary(x => x, x => new Foo(x)));
var qry = new ScanQuery<int, Foo>
{
Local = true,
Filter = withFilter
? new ScanQueryPlatformCacheFilter
{
CacheName = cache.Name
}
: null,
Partition = withPartition
? _grid.GetAffinity(cache.Name).GetPartition(TestUtils.GetPrimaryKey(_grid, cache.Name))
: (int?) null
};
var res = cache.Query(qry);
foreach (var entry in res)
{
var localValue = cache.LocalPeek(entry.Key, CachePeekMode.Platform);
if (withPartition)
{
// Local scan with partition works directly through platform cache.
Assert.AreSame(entry.Value, localValue);
}
else
{
// Local scan without partition works through Java.
Assert.AreNotSame(entry.Value, localValue);
}
}
if (withPartition)
{
Assert.Throws<ObjectDisposedException>(() => res.GetAll());
}
}
/// <summary>
/// Tests that local scan query reserves the partition when <see cref="ScanQuery{TK,TV}.Partition"/> is set.
/// </summary>
[Test]
public void TestLocalScanQueryWithPartitionReservesPartitionAndReleasesItOnDispose()
{
var cache = GetCache<int, Foo>(CacheTestMode.ServerLocal);
var key = TestUtils.GetPrimaryKey(_grid, cache.Name);
var part = _grid.GetAffinity(cache.Name).GetPartition(key);
cache.PutAll(Enumerable.Range(1, 100).ToDictionary(x => x, x => new Foo(x)));
var qry = new ScanQuery<int, Foo>
{
Local = true,
Partition = part
};
Func<bool> isReserved = () => TestUtils.IsPartitionReserved(_grid, cache.Name, part);
Assert.IsFalse(isReserved());
// Full iteration.
using (var cursor = cache.Query(qry))
{
Assert.IsTrue(isReserved());
using (var enumerator = cursor.GetEnumerator())
{
Assert.IsTrue(isReserved());
while (enumerator.MoveNext())
{
Assert.IsTrue(isReserved());
}
Assert.IsFalse(isReserved());
}
Assert.IsFalse(isReserved());
}
Assert.IsFalse(isReserved());
// Partial iteration with LINQ.
using (var cursor = cache.Query(qry))
{
Assert.IsTrue(isReserved());
var item = cursor.FirstOrDefault();
Assert.IsNotNull(item);
// Released because LINQ disposes the iterator.
Assert.IsFalse(isReserved());
}
// Partial iteration.
using (var cursor = cache.Query(qry))
{
Assert.IsTrue(isReserved());
var moved = cursor.GetEnumerator().MoveNext();
Assert.IsTrue(moved);
Assert.IsTrue(isReserved());
}
Assert.IsFalse(isReserved());
// GetAll without using block.
using (var cursor = cache.Query(qry))
{
Assert.IsTrue(isReserved());
var res = cursor.GetAll();
Assert.IsNotEmpty(res);
Assert.IsFalse(isReserved());
}
// Exception in filter.
qry.Filter = new ScanQueryPlatformCacheFilter {FailKey = key};
using (var cursor = cache.Query(qry))
{
Assert.IsTrue(isReserved());
Assert.Throws<SecurityException>(() => cursor.GetAll());
Assert.IsFalse(isReserved());
}
}
/// <summary>
/// Tests that invalid <see cref="ScanQuery{TK,TV}.Partition"/> causes correct exception.
/// </summary>
[Test]
public void TestLocalScanQueryWithInvalidPartitionId()
{
var cache = GetCache<int, Foo>(CacheTestMode.ServerLocal);
var qry = new ScanQuery<int, Foo> {Local = true, Partition = 1024};
var ex = Assert.Throws<IgniteException>(() => cache.Query(qry));
Assert.AreEqual("Invalid partition number: 1024", ex.Message);
}
/// <summary>
/// Tests that local scan query throws an exception when <see cref="ScanQuery{TK,TV}.Partition"/> is specified,
/// but that partition can not be reserved (belongs to remote node).
/// </summary>
[Test]
public void TestLocalScanQueryWithPartitionThrowsOnRemoteKeys()
{
var cache = GetCache<int, Foo>(CacheTestMode.ServerLocal);
var partition = _grid2.GetAffinity(cache.Name)
.GetPrimaryPartitions(_grid2.GetCluster().GetLocalNode())
.First();
var qry = new ScanQuery<int, Foo>
{
Local = true,
Partition = partition
};
var ex = Assert.Throws<InvalidOperationException>(() => cache.Query(qry).GetAll());
Assert.AreEqual(
string.Format("Failed to reserve partition {0}, it does not belong to the local node.", partition),
ex.Message);
}
/// <summary>
/// Tests local scan query on client node.
/// </summary>
[Test]
public void TestLocalScanQueryFromClientNode()
{
var cache = _grid.CreateCache<int, Foo>(TestUtils.TestName);
cache.PutAll(Enumerable.Range(1, 100).ToDictionary(x => x, x => new Foo(x)));
var clientCache = _client.CreateNearCache<int, Foo>(cache.Name, new NearCacheConfiguration(),
new PlatformCacheConfiguration());
// Promote key to near cache.
clientCache.Get(2);
var res = clientCache.Query(new ScanQuery<int, Foo> {Local = true}).GetAll();
// Local scan on client node returns empty collection.
Assert.AreEqual(1, clientCache.GetLocalSize(CachePeekMode.Near));
Assert.AreEqual(1, clientCache.GetLocalSize(CachePeekMode.Platform));
Assert.IsEmpty(res);
}
/// <summary>
/// Tests that expiry policy functionality plays well with platform cache.
/// </summary>
[Test]
public void TestExpiryPolicyRemovesValuesFromPlatformCache(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode)
{
var cache = GetCache<int, Foo>(mode)
.WithExpiryPolicy(new ExpiryPolicy(TimeSpan.FromSeconds(0.2), null, null));
cache[1] = new Foo(1);
Assert.AreEqual(1, cache[1].Bar);
Assert.AreEqual(1, cache.LocalPeek(1, CachePeekMode.Platform).Bar);
Assert.AreEqual(1, cache.Count());
Foo _;
TestUtils.WaitForTrueCondition(() => !cache.TryLocalPeek(1, out _, CachePeekMode.Platform), 3000);
}
/// <summary>
/// Tests server-side platform cache binary mode.
/// </summary>
[Test]
public void TestKeepBinaryServer()
{
// Create server platform cache with binary mode enabled.
var cfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration
{
KeepBinary = true
}
};
var clientCache = _client.CreateCache<int, Foo>(cfg);
var serverCache = _grid2.GetCache<int, object>(cfg.Name);
Assert.IsTrue(serverCache.GetConfiguration().PlatformCacheConfiguration.KeepBinary);
// Put non-binary from client. There is no platform cache on client.
clientCache[1] = new Foo(2);
// Read from platform on server.
var res = (IBinaryObject) serverCache.LocalPeek(1, CachePeekMode.Platform);
Assert.AreEqual(2, res.GetField<int>("Bar"));
}
[Test]
public void TestMultithreadedConcurrentUpdates()
{
var localCache = GetCache<int, Foo>(CacheTestMode.Client);
var remoteCache = GetCache<int, Foo>(CacheTestMode.ServerRemote);
var cancel = false;
const int key = 1;
var id = 1;
remoteCache[1] = new Foo(id);
var localUpdater = Task.Factory.StartNew(() =>
{
// ReSharper disable once AccessToModifiedClosure
while (!cancel)
{
Interlocked.Increment(ref id);
localCache.Put(key, new Foo(id));
}
});
var remoteUpdater = Task.Factory.StartNew(() =>
{
// ReSharper disable once AccessToModifiedClosure
while (!cancel)
{
Interlocked.Increment(ref id);
remoteCache.Put(key, new Foo(id));
}
});
var localReader = Task.Factory.StartNew(() =>
{
// ReSharper disable once AccessToModifiedClosure
while (!cancel)
{
var cur = localCache[key].Bar;
Assert.GreaterOrEqual(id, cur);
}
});
Thread.Sleep(5000);
cancel = true;
Task.WaitAll(localUpdater, remoteUpdater, localReader);
// Get actual value with SQL to bypass caches.
// Actual value may not be equal to the latest id because two threads compete in Put calls.
var actualValue = (int) localCache.Query(new SqlFieldsQuery("select Bar from Foo")).GetAll()[0][0];
Assert.AreEqual(actualValue, localCache[key].Bar, "Local value");
Assert.AreEqual(actualValue, remoteCache[key].Bar, "Remote value");
}
/// <summary>
/// Tests GetAll operation.
/// </summary>
/// <param name="async"></param>
[Test]
public void TestGetAll([Values(true, false)] bool async)
{
var clientCache = GetCache<int, Foo>(CacheTestMode.Client);
var serverCache = GetCache<int, Foo>(CacheTestMode.ServerRemote);
// One entry is in platform cache, another is not.
clientCache[1] = new Foo(1);
serverCache[2] = new Foo(2);
var res = async
? clientCache.GetAllAsync(Enumerable.Range(1, 2)).Result
: clientCache.GetAll(Enumerable.Range(1, 2));
Assert.AreEqual(new[] {1, 2}, res.Select(x => x.Key));
// First entry is from platform cache.
Assert.AreSame(res.First().Value, clientCache.LocalPeek(1, CachePeekMode.Platform));
// Second entry is now in platform cache.
Assert.AreEqual(2, clientCache.LocalPeek(2, CachePeekMode.Platform).Bar);
}
/// <summary>
/// Tests LocalPeek / TryLocalPeek with platform platform cache.
/// </summary>
[Test]
public void TestLocalPeek()
{
var clientCache = GetCache<int, Foo>(CacheTestMode.Client);
var serverCache = GetCache<int, Foo>(CacheTestMode.ServerRemote);
// One entry is in client platform cache, another is not.
clientCache[1] = new Foo(1);
serverCache[2] = new Foo(2);
Foo foo;
Assert.IsTrue(clientCache.TryLocalPeek(1, out foo, CachePeekMode.Platform));
Assert.AreEqual(1, foo.Bar);
Assert.IsTrue(clientCache.TryLocalPeek(1, out foo, CachePeekMode.Platform | CachePeekMode.Near));
Assert.AreEqual(1, foo.Bar);
Assert.IsFalse(clientCache.TryLocalPeek(2, out foo, CachePeekMode.Platform));
Assert.IsFalse(clientCache.TryLocalPeek(2, out foo, CachePeekMode.Near));
Assert.IsFalse(clientCache.TryLocalPeek(2, out foo, CachePeekMode.All));
Assert.AreEqual(2, serverCache.LocalPeek(2, CachePeekMode.Platform).Bar);
Assert.AreEqual(2, serverCache.LocalPeek(2, CachePeekMode.Near).Bar);
Assert.AreSame(serverCache[2], serverCache.LocalPeek(2, CachePeekMode.Platform));
Assert.AreNotSame(serverCache[2], serverCache.LocalPeek(2, CachePeekMode.Near));
}
[Test]
public void TestContainsKey(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode,
[Values(true, false)] bool async)
{
var cache = GetCache<int, int>(mode);
var cache2 = GetCache<int, int>(CacheTestMode.ServerLocal);
var data = Enumerable.Range(1, 100).ToDictionary(x => x, x => x);
cache2.PutAll(data);
var act = async
? (Func<int, bool>) (k => cache.ContainsKeyAsync(k).Result)
: k => cache.ContainsKey(k);
foreach (var key in data.Keys)
{
Assert.IsTrue(act(key));
Assert.IsFalse(act(-key));
}
}
[Test]
public void TestContainsKeys(
[Values(CacheTestMode.ServerLocal, CacheTestMode.ServerRemote, CacheTestMode.Client)] CacheTestMode mode,
[Values(true, false)] bool async)
{
var cache = GetCache<int, int>(mode);
var cache2 = GetCache<int, int>(CacheTestMode.ServerLocal);
var data = Enumerable.Range(1, 100).ToDictionary(x => x, x => x);
cache2.PutAll(data);
var act = async
? (Func<IEnumerable<int>, bool>) (k => cache.ContainsKeysAsync(k).Result)
: k => cache.ContainsKeys(k);
foreach (var key in data.Keys)
{
Assert.IsTrue(act(new[] {key}));
Assert.IsFalse(act(new[] {-key}));
}
Assert.IsTrue(act(data.Keys));
Assert.IsTrue(act(data.Keys.Take(10)));
Assert.IsTrue(act(data.Keys.Skip(10)));
Assert.IsFalse(act(data.Keys.Concat(new[] {-1})));
}
/// <summary>
/// Tests local size on server node.
/// </summary>
[Test]
public void TestGetLocalSizeServer()
{
var cache = GetCache<int, int>(CacheTestMode.ServerRemote, TestUtils.TestName);
Assert.AreEqual(0, cache.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(0, cache.GetLocalSize(CachePeekMode.All));
cache.PutAll(Enumerable.Range(1, 100).ToDictionary(x => x, x => x));
var primary = cache.GetLocalSize(CachePeekMode.Primary);
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Near));
Assert.AreEqual(NearCacheMaxSize + primary, cache.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(NearCacheMaxSize * 2 + primary,
cache.GetLocalSize(CachePeekMode.Near | CachePeekMode.Platform));
Assert.AreEqual(NearCacheMaxSize * 2 + primary,
cache.GetLocalSize(CachePeekMode.Near, CachePeekMode.Platform));
}
/// <summary>
/// Tests local size on client node.
/// </summary>
[Test]
public void TestGetLocalSizeClient()
{
var cache = GetCache<int, int>(CacheTestMode.Client, TestUtils.TestName);
Assert.AreEqual(0, cache.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(0, cache.GetLocalSize(CachePeekMode.All));
cache.PutAll(Enumerable.Range(1, 100).ToDictionary(x => x, x => x));
Assert.AreEqual(0, cache.GetLocalSize());
Assert.AreEqual(0, cache.GetLocalSize(CachePeekMode.Primary | CachePeekMode.Backup));
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Near));
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(NearCacheMaxSize * 2, cache.GetLocalSize(CachePeekMode.All));
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Platform, CachePeekMode.Primary));
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Platform | CachePeekMode.Primary));
Assert.AreEqual(NearCacheMaxSize * 2, cache.GetLocalSize(CachePeekMode.Near | CachePeekMode.Platform));
Assert.AreEqual(NearCacheMaxSize * 2, cache.GetLocalSize(CachePeekMode.Near, CachePeekMode.Platform));
}
/// <summary>
/// Tests that <see cref="CachePeekMode.Platform"/> works with distributed GetSize overloads.
/// </summary>
[Test]
public void TestGetSizeWithPlatform([Values(true, false)] bool longMode,
[Values(true, false)] bool async)
{
var cache = GetCache<int, int>(CacheTestMode.Client, TestUtils.TestName);
var primaryAndPlatform = new[] {CachePeekMode.Primary, CachePeekMode.Platform};
var platform = new[] {CachePeekMode.Platform};
var all = new[] {CachePeekMode.All};
var func =
longMode
? async
? (Func<CachePeekMode[], long>) (m => cache.GetSizeLongAsync(m).Result)
: m => cache.GetSizeLong(m)
: async
? (Func<CachePeekMode[], long>) (m => cache.GetSizeAsync(m).Result)
: m => cache.GetSize(m);
Assert.AreEqual(0, func(all));
Assert.AreEqual(0, func(platform));
cache[1] = 2;
Assert.AreEqual(1, func(platform));
Assert.AreEqual(2, func(primaryAndPlatform));
Assert.AreEqual(3, func(all));
cache[2] = 3;
Assert.AreEqual(2, func(platform));
Assert.AreEqual(4, func(primaryAndPlatform));
Assert.AreEqual(6, func(all));
}
/// <summary>
/// Tests that <see cref="CachePeekMode.Platform"/> works with distributed GetSize overloads
/// with specific partition.
/// </summary>
[Test]
public void TestGetSizeWithPlatformAndPartition([Values(true, false)] bool async)
{
var cache = GetCache<int, int>(CacheTestMode.Client, TestUtils.TestName);
var primaryAndPlatform = new[] {CachePeekMode.Primary, CachePeekMode.Platform};
var platform = new[] {CachePeekMode.Platform};
var all = new[] {CachePeekMode.All};
var func = async
? (Func<int, CachePeekMode[], long>) ((p, m) => cache.GetSizeLongAsync(p, m).Result)
: (p, m) => cache.GetSizeLong(p, m);
const int key = 1;
var part = _grid.GetAffinity(cache.Name).GetPartition(key);
Assert.AreEqual(0, func(part, all));
Assert.AreEqual(0, func(part, platform));
cache[1] = 2;
Assert.AreEqual(1, func(part, platform));
Assert.AreEqual(2, func(part, primaryAndPlatform));
Assert.AreEqual(2, func(part, all));
Assert.AreEqual(0, func(part + 1, platform));
Assert.AreEqual(0, func(part + 1, primaryAndPlatform));
Assert.AreEqual(0, func(part + 1, all));
cache[2] = 3;
Assert.AreEqual(1, func(part, platform));
Assert.AreEqual(2, func(part, primaryAndPlatform));
Assert.AreEqual(2, func(part, all));
}
/// <summary>
/// Tests <see cref="ICache{TK,TV}.GetLocalEntries"/> with <see cref="CachePeekMode.Platform"/>.
/// </summary>
[Test]
public void TestGetLocalEntriesPlatformOnly()
{
var cache = GetCache<int, Foo>(CacheTestMode.Client, TestUtils.TestName);
var keys = Enumerable.Range(1, 3).ToArray();
cache.PutAll(keys.ToDictionary(x => x, x => new Foo(x)));
var localEntries = cache.GetLocalEntries(CachePeekMode.Platform).ToArray();
// Same set of keys.
CollectionAssert.AreEquivalent(keys, localEntries.Select(e => e.Key));
// Returns same instances every time.
CollectionAssert.AreEqual(localEntries.Select(e => e.Value),
cache.GetLocalEntries(CachePeekMode.Platform).Select(e => e.Value));
// Every instance is from platform cache.
foreach (var entry in localEntries)
{
Assert.AreSame(entry.Value, cache[entry.Key]);
}
}
/// <summary>
/// Tests <see cref="ICache{TK,TV}.GetLocalEntries"/> with various modes.
/// </summary>
[Test]
public void TestGetLocalEntriesCombinedModes()
{
var cache = GetCache<int, Foo>(CacheTestMode.ServerLocal, TestUtils.TestName);
var keys = Enumerable.Range(1, 100).ToArray();
cache.PutAll(keys.ToDictionary(x => x, x => new Foo(x)));
Func<CachePeekMode, int[]> getKeys = mode =>
cache.GetLocalEntries(mode).Select(e => e.Key).OrderBy(k => k).ToArray();
var primary = getKeys(CachePeekMode.Primary);
var near = getKeys(CachePeekMode.Near);
var platform = getKeys(CachePeekMode.Platform);
var all = getKeys(CachePeekMode.All);
var all2 = getKeys(CachePeekMode.Primary | CachePeekMode.Near | CachePeekMode.Platform);
CollectionAssert.AreEqual(all, all2);
CollectionAssert.AreEquivalent(all, platform.Concat(primary).Concat(near));
CollectionAssert.AreEquivalent(platform, primary.Concat(near));
}
/// <summary>
/// Tests that backup entries are reflected in platform cache.
/// </summary>
[Test]
public void TestPlatformCachingWithBackups()
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
CacheMode = CacheMode.Partitioned,
Backups = 1,
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
WriteSynchronizationMode = CacheWriteSynchronizationMode.FullSync
};
var cache1 = _grid.CreateCache<int, int>(cfg);
var cache2 = _grid2.GetCache<int, int>(cfg.Name);
const int count = 100;
cache1.PutAll(Enumerable.Range(1, count).ToDictionary(x => x, x => x));
Assert.AreEqual(count, cache1.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(count, cache2.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(42, cache1.LocalPeek(42, CachePeekMode.Platform));
Assert.AreEqual(42, cache2.LocalPeek(42, CachePeekMode.Platform));
cache1[42] = -42;
Assert.AreEqual(-42, cache1.LocalPeek(42, CachePeekMode.Platform));
Assert.AreEqual(-42, cache2.LocalPeek(42, CachePeekMode.Platform));
}
/// <summary>
/// Tests that Replicated cache puts all entries on all nodes to platform cache.
/// </summary>
[Test]
public void TestPlatformCachingReplicated([Values(false, true)] bool readFromBackup)
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
CacheMode = CacheMode.Replicated,
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
WriteSynchronizationMode = CacheWriteSynchronizationMode.FullSync,
ReadFromBackup = readFromBackup
};
var cache1 = _grid.CreateCache<int, int>(cfg);
var cache2 = _grid2.GetCache<int, int>(cfg.Name);
const int count = 100;
cache1.PutAll(Enumerable.Range(1, count).ToDictionary(x => x, x => x));
Assert.AreEqual(count, cache1.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(count, cache2.GetLocalSize(CachePeekMode.Platform));
Assert.AreEqual(42, cache1.LocalPeek(42, CachePeekMode.Platform));
Assert.AreEqual(42, cache2.LocalPeek(42, CachePeekMode.Platform));
cache1[42] = -42;
Assert.AreEqual(-42, cache1.LocalPeek(42, CachePeekMode.Platform));
Assert.AreEqual(-42, cache2.LocalPeek(42, CachePeekMode.Platform));
}
/// <summary>
/// Tests that active transaction disables platform cache.
/// </summary>
[Test]
public void TestPlatformCacheBypassedWithinTransaction()
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
AtomicityMode = CacheAtomicityMode.Transactional,
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
NearConfiguration = new NearCacheConfiguration()
};
var cache = _grid.CreateCache<int, Foo>(cfg);
cache[1] = new Foo(2);
var foo = cache[1];
Assert.AreEqual(2, foo.Bar);
Assert.AreSame(foo, cache[1]);
using (_grid.GetTransactions().TxStart())
{
Assert.AreNotSame(foo, cache[1]);
}
Assert.AreSame(foo, cache[1]);
using (new TransactionScope())
{
cache[2] = new Foo(3);
Assert.IsNotNull(_grid.GetTransactions().Tx);
Assert.AreNotSame(foo, cache[1]);
}
Assert.AreSame(foo, cache[1]);
}
/// <summary>
/// Tests platform cache misconfiguration / type mismatch.
/// </summary>
[Test]
public void TestPlatformCacheTypeMismatchLogsErrorAndUpdatesMainCache()
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
PlatformCacheConfiguration = new PlatformCacheConfiguration
{
KeyTypeName = typeof(int).FullName,
ValueTypeName = typeof(Guid).FullName
}
};
var nearCfg = new NearCacheConfiguration();
var clientCache = _client.CreateCache<int, Foo>(cfg, nearCfg);
var serverCache = _grid.GetCache<int, Foo>(cfg.Name);
// Put Foo, but platform cache expects Guid.
clientCache.GetAndPut(1, new Foo(2));
// Entry is not in platform cache.
Assert.AreEqual(0, clientCache.GetLocalSize(CachePeekMode.Platform));
// Ignite cache is updated.
Assert.AreEqual(2, serverCache[1].Bar);
Assert.AreEqual(2, clientCache[1].Bar);
// Error is logged.
Func<ListLogger.Entry> getEntry = () =>
_logger.Entries.FirstOrDefault(e => e.Message.StartsWith("Failure in Java callback"));
var message = string.Join(" | ", _logger.Entries.Select(e => e.Message));
TestUtils.WaitForTrueCondition(() => getEntry() != null, 3000, message);
}
/// <summary>
/// <see cref="ICache{TK,TV}.LoadCache"/> uses same filter mechanism as <see cref="ScanQuery{TK,TV}"/>.
/// Platform cache should never be used for cache store load filters.
/// </summary>
[Test]
public void TestCacheStoreLoadFilterDoesNotUseNearCache()
{
var cfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration(),
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
CacheStoreFactory = new FailingCacheStore()
};
var cache = _grid.CreateCache<int, Foo>(cfg);
// Put a value to be overwritten from store.
var foo = FailingCacheStore.Foo;
var key = foo.Bar;
cache[key] = new Foo(1);
// Filter asserts that values do not come from platform cache.
var filter = new StoreNoPlatformCacheFilter
{
CacheName = cache.Name
};
cache.LoadCache(filter);
}
/// <summary>
/// Tests platform cache with different eviction configuration on client and server nodes.
/// </summary>
[Test]
public void TestDifferentEvictionPoliciesOnClientAndServer()
{
const int serverMaxSize = 4;
const int clientMaxSize = serverMaxSize * 3;
var serverCfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration
{
EvictionPolicy = new LruEvictionPolicy
{
MaxSize = serverMaxSize
}
}
};
var clientCfg = new NearCacheConfiguration
{
EvictionPolicy = new FifoEvictionPolicy
{
MaxSize = clientMaxSize
}
};
var platformCfg = new PlatformCacheConfiguration();
var serverCache = _grid.CreateCache<int, int>(serverCfg);
var clientCache = _client.CreateNearCache<int, int>(serverCache.Name, clientCfg, platformCfg);
var keys = Enumerable.Range(1, 100).ToList();
keys.ForEach(k => clientCache.Put(k, k));
Assert.AreEqual(clientMaxSize, clientCache.GetLocalSize(CachePeekMode.Near));
Assert.AreEqual(clientMaxSize, clientCache.GetLocalSize(CachePeekMode.Platform));
var expectedKeys = keys.AsEnumerable().Reverse().Take(clientMaxSize).ToArray();
var nearKeys =
clientCache.GetLocalEntries(CachePeekMode.Platform).Select(e => e.Key).ToArray();
CollectionAssert.AreEquivalent(expectedKeys, nearKeys);
}
/// <summary>
/// Tests that <see cref="IDataStreamer{TK,TV}"/> updates platform cache.
/// </summary>
[Test]
public void TestDataStreamerUpdatesPlatformCache()
{
const int entryCount = 10000;
var serverCfg = new CacheConfiguration
{
Name = TestUtils.TestName,
NearConfiguration = new NearCacheConfiguration
{
EvictionPolicy = new LruEvictionPolicy
{
MaxSize = entryCount
}
},
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
var clientCfg = new NearCacheConfiguration
{
EvictionPolicy = new LruEvictionPolicy
{
MaxSize = entryCount
}
};
var platformCfg = new PlatformCacheConfiguration();
var serverCache = _grid.CreateCache<int, int>(serverCfg);
var clientCache = _client.CreateNearCache<int, int>(serverCache.Name, clientCfg, platformCfg);
var data = Enumerable.Range(1, entryCount).ToDictionary(x => x, x => x);
serverCache.PutAll(data);
// Get data on client.
var res = clientCache.GetAll(data.Keys);
Assert.AreEqual(entryCount, res.Count);
// Check that all entries are in platform cache on client.
Assert.AreEqual(entryCount, clientCache.GetLocalSize(CachePeekMode.Near));
Assert.AreEqual(entryCount, clientCache.GetLocalSize(CachePeekMode.Platform));
// Update all entries with streamer.
using (var streamer = _grid2.GetDataStreamer<int, int>(serverCache.Name))
{
streamer.AllowOverwrite = true;
foreach (var entry in data)
{
streamer.Add(entry.Key, entry.Value + 1);
}
}
// Verify that platform cache contains updated entries.
foreach (var entry in data)
{
var key = entry.Key;
var val = entry.Value + 1;
TestUtils.WaitForTrueCondition(() => val == clientCache.LocalPeek(key, CachePeekMode.Platform),
message: string.Format("{0} = {1}", key, val));
TestUtils.WaitForTrueCondition(() => val == serverCache.LocalPeek(key, CachePeekMode.Platform),
message: string.Format("{0} = {1}", key, val));
}
}
/// <summary>
/// Gets the cache instance.
/// </summary>
private ICache<TK, TV> GetCache<TK, TV>(CacheTestMode mode, string name = CacheName)
{
var nearConfiguration = _grid.GetCache<TK, TV>(CacheName).GetConfiguration().NearConfiguration;
var cacheConfiguration = new CacheConfiguration
{
NearConfiguration = nearConfiguration,
Name = name,
PlatformCacheConfiguration = new PlatformCacheConfiguration()
};
return GetIgnite(mode).GetOrCreateCache<TK, TV>(cacheConfiguration, nearConfiguration);
}
/// <summary>
/// Gets Ignite instance for mode.
/// </summary>
private IIgnite GetIgnite(CacheTestMode mode)
{
return new[] {_grid, _grid2, _client}[(int) mode];
}
/// <summary>
/// Tests that eviction policy removes platform cache data for the key.
/// </summary>
private void TestEvictionPolicyRemovesPlatformCacheValue(CacheTestMode mode, ICache<int, Foo> cache)
{
// Use non-primary keys: primary keys are not evicted.
var items = TestUtils
.GetKeys(GetIgnite(mode), cache.Name, primary: false)
.Take(NearCacheMaxSize + 1)
.Select(x => new Foo(x))
.ToArray();
var cachedItems = new List<Foo>();
foreach (var item in items)
{
cache[item.Bar] = item;
cachedItems.Add(cache[item.Bar]);
}
// Recent items are in platform cache:
Assert.AreEqual(NearCacheMaxSize, cache.GetLocalSize(CachePeekMode.Platform));
foreach (var item in cachedItems.Skip(items.Length - NearCacheMaxSize))
{
Assert.AreSame(item, cache[item.Bar]);
}
// First item is not in platform cache and is deserialized on get:
var localItem = items[0];
var key = localItem.Bar;
Foo _;
Assert.IsFalse(cache.TryLocalPeek(key, out _, CachePeekMode.Platform));
var fromCache = cache[key];
Assert.AreNotSame(localItem, fromCache);
// And now it is platform again:
Assert.IsTrue(cache.TryLocalPeek(key, out _, CachePeekMode.Platform));
Assert.AreSame(cache[key], cache[key]);
}
private void WaitForRebalance()
{
TestUtils.WaitForTrueCondition(() => _grid2.GetAffinity(CacheName).MapKeyToNode(1).IsLocal, 2000);
}
/** */
public enum CacheTestMode
{
ServerLocal,
ServerRemote,
Client
}
}
}