You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2022/12/29 12:29:27 UTC
[ignite] branch master updated: IGNITE-18427 .NET: Fix platform cache invalidation on client nodes with near cache (#10465)
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new db7758ce66b IGNITE-18427 .NET: Fix platform cache invalidation on client nodes with near cache (#10465)
db7758ce66b is described below
commit db7758ce66bef167e14030ceaee2ef34ffb1e696
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Thu Dec 29 15:29:18 2022 +0300
IGNITE-18427 .NET: Fix platform cache invalidation on client nodes with near cache (#10465)
* Remove platform cache entry when corresponding `GridCacheMapEntry` is not `valid`.
* Add a test where two thick client nodes with near cache connect to different backup server nodes.
---
.../processors/cache/GridCacheMapEntry.java | 14 +-
.../PlatformCachePartialClientConnectionTest.cs | 143 +++++++++++++++++++++
.../Cache/Platform/PlatformCacheTest.cs | 5 +-
.../platforms/dotnet/Apache.Ignite.Core/IIgnite.cs | 1 -
4 files changed, 155 insertions(+), 8 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index d939635cc27..f45f803136d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -6718,18 +6718,22 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
if (!hasPlatformCache())
return;
- PlatformProcessor proc = this.cctx.kernalContext().platform();
+ PlatformProcessor proc = cctx.kernalContext().platform();
if (!proc.hasContext() || !proc.context().isPlatformCacheSupported())
return;
try {
- CacheObjectContext ctx = this.cctx.cacheObjectContext();
+ CacheObjectContext ctx = cctx.cacheObjectContext();
+ byte[] keyBytes = key.valueBytes(ctx);
// val is null when entry is removed.
- byte[] keyBytes = this.key.valueBytes(ctx);
- byte[] valBytes = val == null ? null : val.valueBytes(ctx);
+ // valid(ver) is false when near cache entry is out of sync.
+ boolean valid = val != null && ver != null && valid(ver);
- proc.context().updatePlatformCache(this.cctx.cacheId(), keyBytes, valBytes, partition(), ver);
+ // null valBytes means that entry should be removed from platform cache.
+ byte[] valBytes = valid ? val.valueBytes(ctx) : null;
+
+ proc.context().updatePlatformCache(cctx.cacheId(), keyBytes, valBytes, partition(), ver);
}
catch (Throwable e) {
U.error(log, "Failed to update Platform Cache: " + e);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCachePartialClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCachePartialClientConnectionTest.cs
new file mode 100644
index 00000000000..da9bdd7f6e7
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCachePartialClientConnectionTest.cs
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Cache.Platform
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Cluster;
+ using Apache.Ignite.Core.Discovery.Tcp;
+ using Apache.Ignite.Core.Discovery.Tcp.Static;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests platform cache with thick clients connected to different parts of the cluster.
+ /// </summary>
+ public class PlatformCachePartialClientConnectionTest
+ {
+ private const string CacheName = "cache1";
+ private const string AttrMacs = "org.apache.ignite.macs";
+
+ private const int Key = 1;
+ private const int InitialValue = 0;
+
+ [TearDown]
+ public void TearDown()
+ {
+ Ignition.StopAll(true);
+ }
+
+ /// <summary>
+ /// Tests that thick client connected only to backup node 1 updates a value,
+ /// and another thick client connected to a different backup node sees the update in Platform Cache.
+ /// </summary>
+ [Test]
+ public static void TestPutFromOneClientGetFromAnother()
+ {
+ // Start 3 servers.
+ var servers = Enumerable.Range(0, 3)
+ .Select(i => Ignition.Start(GetConfiguration(false, i, 0)))
+ .ToArray();
+
+ CreateCache(servers[0]);
+
+ // Start 2 thick clients, connect to different backup nodes only (not entire cluster).
+ var primaryAndBackups = servers[0].GetAffinity(CacheName).MapKeyToPrimaryAndBackups(Key);
+ var backupServer1Mac = GetMac(primaryAndBackups[1]);
+ var backupServer2Mac = GetMac(primaryAndBackups[2]);
+
+ var client1 = Ignition.Start(GetConfiguration(true, backupServer1Mac, backupServer1Mac));
+ var client2 = Ignition.Start(GetConfiguration(true, backupServer2Mac, backupServer2Mac));
+
+ // Check initial value.
+ var client1Cache = client1.GetOrCreateNearCache<int, int>(CacheName, new NearCacheConfiguration());
+ var client2Cache = client2.GetOrCreateNearCache<int, int>(CacheName, new NearCacheConfiguration());
+
+ var client1Value = client1Cache.Get(Key);
+ var client2Value = client2Cache.Get(Key);
+
+ Assert.AreEqual(InitialValue, client1Value);
+ Assert.AreEqual(InitialValue, client2Value);
+
+ // Update value from client 1.
+ const int newValue = 1;
+ client1Cache.Put(Key, newValue);
+
+ // Read value from client 1 and 2.
+ client1Value = client1Cache.Get(Key);
+ client2Value = client2Cache.Get(Key);
+
+ Assert.AreEqual(newValue, client1Value);
+ Assert.AreEqual(newValue, client2Value);
+ }
+
+ private static int GetMac(IClusterNode node) => Convert.ToInt32(node.Attributes[AttrMacs]);
+
+ private static IgniteConfiguration GetConfiguration(bool client, int localMac, int remoteMac)
+ {
+ var name = (client ? "client" : "server") + localMac;
+ var remotePort = 48500 + remoteMac;
+
+ var discoverySpi = new TcpDiscoverySpi
+ {
+ IpFinder = new TcpDiscoveryStaticIpFinder
+ {
+ Endpoints = new List<string> { $"127.0.0.1:{remotePort}" }
+ }
+ };
+
+ if (!client)
+ {
+ discoverySpi.LocalPort = 48500 + localMac;
+ discoverySpi.LocalPortRange = 1;
+ }
+
+ var igniteConfig = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ ClientMode = client,
+ IgniteInstanceName = name,
+ // ConsistentId = name,
+ UserAttributes = new Dictionary<string, object>
+ {
+ [$"override.{AttrMacs}"] = localMac.ToString()
+ },
+ DiscoverySpi = discoverySpi
+ };
+
+ return igniteConfig;
+ }
+
+ private static void CreateCache(IIgnite ignite)
+ {
+ var cacheConfig = new CacheConfiguration(CacheName)
+ {
+ CacheMode = CacheMode.Replicated,
+ ReadFromBackup = true, // Does not reproduce when false.
+ PlatformCacheConfiguration = new PlatformCacheConfiguration
+ {
+ KeyTypeName = typeof(int).FullName,
+ ValueTypeName = typeof(int).FullName
+ }
+ };
+
+ var cache = ignite.GetOrCreateCache<int, int>(cacheConfig);
+ cache.Put(Key, InitialValue);
+ }
+ }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCacheTest.cs
index ccfc834dee0..ea77dc96809 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCacheTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Platform/PlatformCacheTest.cs
@@ -1229,13 +1229,14 @@ namespace Apache.Ignite.Core.Tests.Cache.Platform
/// Tests that Replicated cache puts all entries on all nodes to platform cache.
/// </summary>
[Test]
- public void TestPlatformCachingReplicated()
+ public void TestPlatformCachingReplicated([Values(false, true)] bool readFromBackup)
{
var cfg = new CacheConfiguration(TestUtils.TestName)
{
CacheMode = CacheMode.Replicated,
PlatformCacheConfiguration = new PlatformCacheConfiguration(),
- WriteSynchronizationMode = CacheWriteSynchronizationMode.FullSync
+ WriteSynchronizationMode = CacheWriteSynchronizationMode.FullSync,
+ ReadFromBackup = readFromBackup
};
var cache1 = _grid.CreateCache<int, int>(cfg);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index 0b9c67ddcda..dd72c71a94e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -33,7 +33,6 @@ namespace Apache.Ignite.Core
using Apache.Ignite.Core.Log;
using Apache.Ignite.Core.Lifecycle;
using Apache.Ignite.Core.Messaging;
- using Apache.Ignite.Core.PersistentStore;
using Apache.Ignite.Core.Plugin;
using Apache.Ignite.Core.Services;
using Apache.Ignite.Core.Transactions;