From b9710350506181c702109b5f5209b906c02be3c4 Mon Sep 17 00:00:00 2001 From: "joe.fialli" Date: Tue, 17 Dec 2024 17:43:25 -0500 Subject: [PATCH] Bug 37315342 - [37264961->14.1.1.0.20] CQC constructor with fCacheValues of false should configure lite mapListener (NET-v 14.1.2->NET-v14.1.1) Validated running shelf build of Coh-NET-14.1.1.0, #992. [git-p4: depot-paths = "//dev/release.net/coherence-net-v14.1.1.0/": change = 113012] --- .../Net/Cache/ContinuousQueryCache.cs | 25 +- .../Net/Cache/CQCProxyTests.cs | 233 +++++++++++++++++- .../Net/Cache/ContinuousQueryCacheTests.cs | 195 ++++++++++++++- 3 files changed, 443 insertions(+), 10 deletions(-) diff --git a/src/Coherence/Net/Cache/ContinuousQueryCache.cs b/src/Coherence/Net/Cache/ContinuousQueryCache.cs index 32d36bf..be42f1d 100644 --- a/src/Coherence/Net/Cache/ContinuousQueryCache.cs +++ b/src/Coherence/Net/Cache/ContinuousQueryCache.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. * * Licensed under the Universal Permissive License v 1.0 as shown at * https://oss.oracle.com/licenses/upl. @@ -134,11 +134,15 @@ public virtual bool IsCacheValues /// true if this object caches values locally, and false if it /// relies on the underlying INamedCache. /// + ///

+ /// Note that a non-null or a isLite parameter of false + /// passed to forces + /// CacheValues to always be true.

public virtual bool CacheValues { get { - return m_cacheValues || IsObserved; + return m_cacheValues || IsObserved || Transformer != null; } set { @@ -512,6 +516,7 @@ public ContinuousQueryCache(INamedCache cache, IFilter filter, IValueExtractor t /// /// Pass true to cache both the keys and values of the /// materialized view locally, or false to only cache the keys. + /// Override of false described in . /// public ContinuousQueryCache(INamedCache cache, IFilter filter, bool isCacheValues) : this(() => cache, filter, isCacheValues, null, null) @@ -562,6 +567,7 @@ public ContinuousQueryCache(INamedCache cache, IFilter filter, ICacheListener li /// /// Pass true to cache both the keys and values of the /// materialized view locally, or false to only cache the keys. + /// Override of false described in CacheValues. /// /// /// The optional ICacheListener that will receive all events @@ -571,7 +577,11 @@ public ContinuousQueryCache(INamedCache cache, IFilter filter, ICacheListener li /// The transformer that should be used to convert values from the /// underlying cache before storing them locally /// - public ContinuousQueryCache(Func supplierCache, IFilter filter, bool cacheValues, + ///

+ /// Note when parameter cacheValues is false, it is inferred that provided parameter + /// cacheListener is a lite listener as described by isLite parameter of + /// .

+ public ContinuousQueryCache(Func supplierCache, IFilter filter, bool cacheValues, ICacheListener cacheListener, IValueExtractor transformer) { INamedCache cache = supplierCache(); @@ -601,6 +611,9 @@ public ContinuousQueryCache(Func supplierCache, IFilter filter, boo m_state = CacheState.Disconnected; m_cacheListener = cacheListener; + // initialize IsObserved on whether a standard (non-lite) listener passed in at construction time + m_hasListeners = cacheListener != null && cacheValues; + // by including information about the underlying cache, filter and // transformer, the resulting cache name is convoluted but extremely // helpful for tasks such as debugging @@ -2596,13 +2609,13 @@ protected IObservableCache EnsureInternalCache() if (m_cacheLocal == null) { IObservableCache cacheLocal = m_cacheLocal = InstantiateInternalCache(); - ICacheListener cacheListener = m_cacheListener; + ICacheListener cacheListener = m_cacheListener; + bool isLite = !CacheValues; if (cacheListener != null) { // the initial listener has to hear the initial events EnsureEventDispatcher(); - cacheLocal.AddCacheListener(InstantiateEventRouter(cacheListener, false)); - m_hasListeners = true; + cacheLocal.AddCacheListener(InstantiateEventRouter(cacheListener, isLite), (IFilter) null, isLite); } } return m_cacheLocal; diff --git a/tests/Coherence.Tests/Net/Cache/CQCProxyTests.cs b/tests/Coherence.Tests/Net/Cache/CQCProxyTests.cs index adb6c85..6062311 100644 --- a/tests/Coherence.Tests/Net/Cache/CQCProxyTests.cs +++ b/tests/Coherence.Tests/Net/Cache/CQCProxyTests.cs @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. * * Licensed under the Universal Permissive License v 1.0 as shown at - * http://oss.oracle.com/licenses/upl. + * https://oss.oracle.com/licenses/upl. */ using System; using System.Collections; @@ -116,6 +116,112 @@ public void TestEvents() Assert.AreEqual(SOME_DATA, listener.GetActualTotal()); } + /// + /// TestEvents with CacheValues of false. + /// + [Test] + public void TestEventsNoValues() + { + // start the ProxyService on just one cluster node + IInvocationService invocationService = RestartProxy(null); + + // put data items into inner cache to generate events + INamedCache testCache = GetCache("proxy-stop-test"); + testCache.Clear(); + IDictionary dict = new Hashtable(); + for (int i = 0; i < SOME_DATA; i++) + { + dict.Add("TestKey" + i, i); + } + testCache.InsertAll(dict); + + // create listener for CQC + ValidateLiteListener listener = new ValidateLiteListener(SOME_DATA); + + // instantiate the CQC, will start the test running. + ContinuousQueryCache queryCache = + new ContinuousQueryCache(() => testCache, AlwaysFilter.Instance, + false, listener, null); + theCQC = queryCache; + Assert.IsFalse(queryCache.CacheValues); + + // instantiate a service listener to receive memberLeft event + fMemberLeft = false; + testCache.CacheService.MemberLeft += new MemberEventHandler(OnMemberLeft); + + // allow test time to complete + using (ThreadTimeout t = ThreadTimeout.After(30000)) + { + while (listener.GetActualTotal() < SOME_DATA) + { + Blocking.Sleep(250); + } + } + + // check listener received the correct number of events. + Assert.AreEqual(SOME_DATA, listener.GetActualTotal()); + listener.ResetActualTotal(); + + // restart proxy + RestartProxy(invocationService); + + using (ThreadTimeout t = ThreadTimeout.After(30000)) + { + while (!fMemberLeft) + { + Blocking.Sleep(250); + } + } + + // ping the CQC to make it realize the cache needs restart + theCQC.Contains("junkstuff"); + + // allow test time to complete. + using (ThreadTimeout t = ThreadTimeout.After(30000)) + { + while (listener.GetActualTotal() < SOME_DATA) + { + Blocking.Sleep(250); + } + } + + Assert.AreEqual(SOME_DATA, listener.GetActualTotal()); + } + + /// + /// TestEvents with CacheValues of false. After standard listener (non-lite) added, CacheValues overriden to true. + /// + [Test] + public void TestEventsNoValuesToObservable() + { + // start the ProxyService on just one cluster node + IInvocationService invocationService = RestartProxy(null); + + // put data items into inner cache to generate events + INamedCache testCache = GetCache("proxy-stop-test"); + testCache.Clear(); + IDictionary dict = new Hashtable(); + for (int i = 0; i < SOME_DATA; i++) + { + dict.Add("TestKey" + i, i); + } + testCache.InsertAll(dict); + + // create listener for CQC + ValidateLiteListener listener = new ValidateLiteListener(SOME_DATA); + + // instantiate the CQC, will start the test running. + ContinuousQueryCache queryCache = new ContinuousQueryCache(() => testCache, AlwaysFilter.Instance, false, listener, null); + theCQC = queryCache; + Assert.IsFalse(queryCache.CacheValues); + + // add standard (non-lite) listener + TestCQCListener listenerStandard = new TestCQCListener(SOME_DATA); + bool isLite = false; + queryCache.AddCacheListener(listenerStandard, AlwaysFilter.Instance, isLite); + Assert.IsTrue(queryCache.CacheValues); + } + /** * utility method to stop and restart the proxy. */ @@ -263,6 +369,129 @@ public void ResetActualTotal() } + // ----- data members ----------------------------------------------- + + /** + * Number of insert events actually received + */ + int m_cActualInserts; + + /** + * Number of update events actually received + */ + int m_cActualUpdates; + + /** + * Number of delete events actually received + */ + int m_cActualDeletes; + + /** + * Number of events listener should receive + */ + int m_cCount; + } + #endregion + + // ----- inner class: ValidateLiteListener -------------------------------------- + + /** + * MapListener that continuously receives events from the cache. + */ + #region Helper class + + class ValidateLiteListener : ICacheListener + { + + public ValidateLiteListener(int count) + { + m_cCount = count; + m_cActualInserts = 0; + m_cActualUpdates = 0; + m_cActualDeletes = 0; + } + + public int Count + { + get { return m_cCount; } + set { m_cCount = value; } + } + + /** + * Number of insert events listener actually received. + * + * @return number of event received + */ + public int ActualInserts + { + get { return m_cActualInserts; } + set { m_cActualInserts = value; } + } + + /** + * Number of update events listener actually received. + * + * @return number of event received + */ + public int ActualUpdates + { + get { return m_cActualUpdates; } + set { m_cActualUpdates = value; } + } + + /** + * Number of delete events listener actually received. + * + * @return number of event received + */ + public int ActualDeletes + { + get { return m_cActualDeletes; } + set { m_cActualDeletes = value; } + } + + public void EntryUpdated(CacheEventArgs evt) + { + m_cActualUpdates++; + Assert.AreEqual(evt.NewValue, null); + Assert.AreEqual(evt.OldValue, null); + } + + public void EntryInserted(CacheEventArgs evt) + { + m_cActualInserts++; + Assert.AreEqual(evt.NewValue, null); + Assert.AreEqual(evt.OldValue, null); + } + + public void EntryDeleted(CacheEventArgs evt) + { + m_cActualDeletes++; + Assert.AreEqual(evt.OldValue, null); + } + + /** + * Total number of events listener actually received. + * + * @return number of event received + */ + public int GetActualTotal() + { + return m_cActualInserts+m_cActualUpdates+m_cActualDeletes; + } + + /** + * Reset the number of events received. + * + */ + public void ResetActualTotal() + { + m_cActualUpdates = 0; + m_cActualInserts = 0; + m_cActualDeletes = 0; + } + + // ----- data members ----------------------------------------------- /** diff --git a/tests/Coherence.Tests/Net/Cache/ContinuousQueryCacheTests.cs b/tests/Coherence.Tests/Net/Cache/ContinuousQueryCacheTests.cs index 5ec9ab1..9211523 100644 --- a/tests/Coherence.Tests/Net/Cache/ContinuousQueryCacheTests.cs +++ b/tests/Coherence.Tests/Net/Cache/ContinuousQueryCacheTests.cs @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. * * Licensed under the Universal Permissive License v 1.0 as shown at - * http://oss.oracle.com/licenses/upl. + * https://oss.oracle.com/licenses/upl. */ using System; using System.Collections; @@ -831,6 +831,75 @@ public void TestCoh2532() Console.Out.WriteLine(cqc); } + [Test] + public void TestLiteListener() + { + INamedCache remoteCache = GetAndPopulateNamedCache("dist-extend-direct"); + + ValidateLiteListener listener = new ValidateLiteListener(NUM_INSERTS); + ContinuousQueryCache theCQC = + new ContinuousQueryCache(() => remoteCache, AlwaysFilter.Instance, + false, listener, null); + + Assert.IsFalse(theCQC.CacheValues); + Assert.That(() => theCQC.State, Is.EqualTo(ContinuousQueryCache.CacheState.Synchronized).After(500, 50)); + Assert.That(() => listener.GetActualTotal(), Is.EqualTo(NUM_INSERTS).After(500, 50)); + Assert.That(theCQC.IsActive, Is.True); + } + + [Test] + public void TestLiteListenerToObservable() + { + INamedCache remoteCache = GetAndPopulateNamedCache("dist-extend-direct"); + + ValidateLiteListener listener = new ValidateLiteListener(NUM_INSERTS); + ContinuousQueryCache theCQC = + new ContinuousQueryCache(() => remoteCache, AlwaysFilter.Instance, false, + listener, null); + + Assert.IsFalse(theCQC.CacheValues); + Assert.That(() => theCQC.State, Is.EqualTo(ContinuousQueryCache.CacheState.Synchronized).After(500, 50)); + Assert.That(() => listener.GetActualTotal(), Is.EqualTo(NUM_INSERTS).After(500, 50)); + Assert.That(theCQC.IsActive, Is.True); + + // add standard (non-lite) listener and validate that CacheValues is overriden to true. + bool isLite = false; + SyncListener listenerStandard = new SyncListener(); + + theCQC.AddCacheListener(listenerStandard, AlwaysFilter.Instance, isLite); + Assert.IsTrue(theCQC.CacheValues); + } + + [Test] + public void TestTransformerNoCacheValues() + { + INamedCache cache = CacheFactory.GetCache("dist-extend-direct"); + cache.Clear(); + + cache.Add(1, new Address("111 Main St", "Burlington", "MA", "01803")); + cache.Add(2, new Address("222 Main St", "Lutz", "FL", "33549")); + + TestCacheListener listener = new TestCacheListener(); + IValueExtractor transformer = new UniversalExtractor("City"); + ContinuousQueryCache cqc = + new ContinuousQueryCache(() => cache, AlwaysFilter.Instance, false, + listener, transformer); + + // assert that cacheValues of false is overridden by non-null Transformer. + Assert.IsTrue(cqc.IsReadOnly); + Assert.IsTrue(cqc.CacheValues); + + Assert.AreEqual("Burlington", cqc[1]); + Assert.AreEqual("Lutz", cqc[2]); + + cache.Add(3, new Address("333 Main St", "Belgrade", "Serbia", "11000")); + Assert.AreEqual("Belgrade", cqc[3]); + cache.Add(3, new Address("333 Main St", "Beograd", "Srbija", "11000")); + Assert.AreEqual("Beograd", cqc[3]); + + Console.Out.WriteLine(cqc); + } + [Test] public void TestCoh10013() { @@ -1462,5 +1531,127 @@ internal class TestNcdListener : TestCacheListener, INamedCacheDeactivationListe public const int NUM_INSERTS = 100; #endregion + + // ----- inner class: ValidateLiteListener -------------------------------------- + + /** + * MapListener that continuously receives events from the cache. + */ + #region Helper class + + class ValidateLiteListener : ICacheListener + { + public ValidateLiteListener(int count) + { + m_cCount = count; + m_cActualInserts = 0; + m_cActualUpdates = 0; + m_cActualDeletes = 0; + } + + public int Count + { + get { return m_cCount; } + set { m_cCount = value; } + } + + /** + * Number of insert events listener actually received. + * + * @return number of event received + */ + public int ActualInserts + { + get { return m_cActualInserts; } + set { m_cActualInserts = value; } + } + + /** + * Number of update events listener actually received. + * + * @return number of event received + */ + public int ActualUpdates + { + get { return m_cActualUpdates; } + set { m_cActualUpdates = value; } + } + + /** + * Number of delete events listener actually received. + * + * @return number of event received + */ + public int ActualDeletes + { + get { return m_cActualDeletes; } + set { m_cActualDeletes = value; } + } + + public void EntryUpdated(CacheEventArgs evt) + { + m_cActualUpdates++; + Assert.AreEqual(evt.NewValue, null); + Assert.AreEqual(evt.OldValue, null); + } + + public void EntryInserted(CacheEventArgs evt) + { + m_cActualInserts++; + Assert.AreEqual(evt.NewValue, null); + Assert.AreEqual(evt.OldValue, null); + } + + public void EntryDeleted(CacheEventArgs evt) + { + m_cActualDeletes++; + Assert.AreEqual(evt.OldValue, null); + } + + /** + * Total number of events listener actually received. + * + * @return number of event received + */ + public int GetActualTotal() + { + return m_cActualInserts+m_cActualUpdates+m_cActualDeletes; + } + + /** + * Reset the number of events received. + * + */ + public void ResetActualTotal() + { + m_cActualUpdates = 0; + m_cActualInserts = 0; + m_cActualDeletes = 0; + } + + + // ----- data members ----------------------------------------------- + + /** + * Number of insert events actually received + */ + int m_cActualInserts; + + /** + * Number of update events actually received + */ + int m_cActualUpdates; + + /** + * Number of delete events actually received + */ + int m_cActualDeletes; + + /** + * Number of events listener should receive + */ + int m_cCount; + } + #endregion } }