This is an automated email from the ASF dual-hosted git repository.

alexpl 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 794a536737f IGNITE-22189 Add expiry policy info to CacheView - Fixes 
#11357.
794a536737f is described below

commit 794a536737f316765e83cb49d661f80849d3bd47
Author: Maksim Davydov <[email protected]>
AuthorDate: Mon Jun 10 18:51:00 2024 +0500

    IGNITE-22189 Add expiry policy info to CacheView - Fixes #11357.
    
    Signed-off-by: Aleksey Plekhanov <[email protected]>
---
 .../ignite/jdbc/thin/JdbcThinMetadataSelfTest.java |   1 +
 .../systemview/walker/CacheViewWalker.java         | 176 +++++++++++----------
 .../cache/IgniteCacheOffheapManager.java           |   8 +
 .../cache/IgniteCacheOffheapManagerImpl.java       |  16 ++
 .../cache/persistence/GridCacheOffheapManager.java |  33 ++++
 .../ignite/spi/systemview/view/CacheView.java      |  80 +++++++++-
 .../metric/SystemViewCacheExpiryPolicyTest.java    | 114 +++++++++++++
 .../ignite/internal/metric/SystemViewSelfTest.java | 110 +++++++++++++
 .../ignite/testsuites/IgniteCacheTestSuite13.java  |   2 +
 9 files changed, 452 insertions(+), 88 deletions(-)

diff --git 
a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
 
b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
index 135c6fc6a24..82b4fc533e0 100644
--- 
a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
+++ 
b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
@@ -708,6 +708,7 @@ public class JdbcThinMetadataSelfTest extends 
JdbcThinAbstractSelfTest {
                 "SYS.CACHES.NEAR_CACHE_EVICTION_POLICY_FACTORY.null",
                 "SYS.CACHES.NEAR_CACHE_START_SIZE.null",
                 "SYS.CACHES.DEFAULT_LOCK_TIMEOUT.null",
+                "SYS.CACHES.HAS_EXPIRING_ENTRIES.null",
                 "SYS.CACHES.INTERCEPTOR.null",
                 "SYS.CACHES.CACHE_STORE_FACTORY.null",
                 "SYS.CACHES.IS_STORE_KEEP_BINARY.null",
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CacheViewWalker.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CacheViewWalker.java
index cc98a093710..c59e8f96b74 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CacheViewWalker.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CacheViewWalker.java
@@ -54,49 +54,50 @@ public class CacheViewWalker implements 
SystemViewRowAttributeWalker<CacheView>
         v.accept(16, "evictionFilter", String.class);
         v.accept(17, "evictionPolicyFactory", String.class);
         v.accept(18, "expiryPolicyFactory", String.class);
-        v.accept(19, "interceptor", String.class);
-        v.accept(20, "isCopyOnRead", boolean.class);
-        v.accept(21, "isEagerTtl", boolean.class);
-        v.accept(22, "isEncryptionEnabled", boolean.class);
-        v.accept(23, "isEventsDisabled", boolean.class);
-        v.accept(24, "isInvalidate", boolean.class);
-        v.accept(25, "isLoadPreviousValue", boolean.class);
-        v.accept(26, "isManagementEnabled", boolean.class);
-        v.accept(27, "isNearCacheEnabled", boolean.class);
-        v.accept(28, "isOnheapCacheEnabled", boolean.class);
-        v.accept(29, "isReadFromBackup", boolean.class);
-        v.accept(30, "isReadThrough", boolean.class);
-        v.accept(31, "isSqlEscapeAll", boolean.class);
-        v.accept(32, "isSqlOnheapCacheEnabled", boolean.class);
-        v.accept(33, "isStatisticsEnabled", boolean.class);
-        v.accept(34, "isStoreKeepBinary", boolean.class);
-        v.accept(35, "isWriteBehindEnabled", boolean.class);
-        v.accept(36, "isWriteThrough", boolean.class);
-        v.accept(37, "maxConcurrentAsyncOperations", int.class);
-        v.accept(38, "maxQueryIteratorsCount", int.class);
-        v.accept(39, "nearCacheEvictionPolicyFactory", String.class);
-        v.accept(40, "nearCacheStartSize", int.class);
-        v.accept(41, "nodeFilter", String.class);
-        v.accept(42, "partitionLossPolicy", PartitionLossPolicy.class);
-        v.accept(43, "queryDetailMetricsSize", int.class);
-        v.accept(44, "queryParallelism", int.class);
-        v.accept(45, "rebalanceBatchSize", int.class);
-        v.accept(46, "rebalanceBatchesPrefetchCount", long.class);
-        v.accept(47, "rebalanceDelay", long.class);
-        v.accept(48, "rebalanceMode", CacheRebalanceMode.class);
-        v.accept(49, "rebalanceOrder", int.class);
-        v.accept(50, "rebalanceThrottle", long.class);
-        v.accept(51, "rebalanceTimeout", long.class);
-        v.accept(52, "sqlIndexMaxInlineSize", int.class);
-        v.accept(53, "sqlOnheapCacheMaxSize", int.class);
-        v.accept(54, "sqlSchema", String.class);
-        v.accept(55, "topologyValidator", String.class);
-        v.accept(56, "writeBehindBatchSize", int.class);
-        v.accept(57, "writeBehindCoalescing", boolean.class);
-        v.accept(58, "writeBehindFlushFrequency", long.class);
-        v.accept(59, "writeBehindFlushSize", int.class);
-        v.accept(60, "writeBehindFlushThreadCount", int.class);
-        v.accept(61, "writeSynchronizationMode", 
CacheWriteSynchronizationMode.class);
+        v.accept(19, "hasExpiringEntries", String.class);
+        v.accept(20, "interceptor", String.class);
+        v.accept(21, "isCopyOnRead", boolean.class);
+        v.accept(22, "isEagerTtl", boolean.class);
+        v.accept(23, "isEncryptionEnabled", boolean.class);
+        v.accept(24, "isEventsDisabled", boolean.class);
+        v.accept(25, "isInvalidate", boolean.class);
+        v.accept(26, "isLoadPreviousValue", boolean.class);
+        v.accept(27, "isManagementEnabled", boolean.class);
+        v.accept(28, "isNearCacheEnabled", boolean.class);
+        v.accept(29, "isOnheapCacheEnabled", boolean.class);
+        v.accept(30, "isReadFromBackup", boolean.class);
+        v.accept(31, "isReadThrough", boolean.class);
+        v.accept(32, "isSqlEscapeAll", boolean.class);
+        v.accept(33, "isSqlOnheapCacheEnabled", boolean.class);
+        v.accept(34, "isStatisticsEnabled", boolean.class);
+        v.accept(35, "isStoreKeepBinary", boolean.class);
+        v.accept(36, "isWriteBehindEnabled", boolean.class);
+        v.accept(37, "isWriteThrough", boolean.class);
+        v.accept(38, "maxConcurrentAsyncOperations", int.class);
+        v.accept(39, "maxQueryIteratorsCount", int.class);
+        v.accept(40, "nearCacheEvictionPolicyFactory", String.class);
+        v.accept(41, "nearCacheStartSize", int.class);
+        v.accept(42, "nodeFilter", String.class);
+        v.accept(43, "partitionLossPolicy", PartitionLossPolicy.class);
+        v.accept(44, "queryDetailMetricsSize", int.class);
+        v.accept(45, "queryParallelism", int.class);
+        v.accept(46, "rebalanceBatchSize", int.class);
+        v.accept(47, "rebalanceBatchesPrefetchCount", long.class);
+        v.accept(48, "rebalanceDelay", long.class);
+        v.accept(49, "rebalanceMode", CacheRebalanceMode.class);
+        v.accept(50, "rebalanceOrder", int.class);
+        v.accept(51, "rebalanceThrottle", long.class);
+        v.accept(52, "rebalanceTimeout", long.class);
+        v.accept(53, "sqlIndexMaxInlineSize", int.class);
+        v.accept(54, "sqlOnheapCacheMaxSize", int.class);
+        v.accept(55, "sqlSchema", String.class);
+        v.accept(56, "topologyValidator", String.class);
+        v.accept(57, "writeBehindBatchSize", int.class);
+        v.accept(58, "writeBehindCoalescing", boolean.class);
+        v.accept(59, "writeBehindFlushFrequency", long.class);
+        v.accept(60, "writeBehindFlushSize", int.class);
+        v.accept(61, "writeBehindFlushThreadCount", int.class);
+        v.accept(62, "writeSynchronizationMode", 
CacheWriteSynchronizationMode.class);
     }
 
     /** {@inheritDoc} */
@@ -120,53 +121,54 @@ public class CacheViewWalker implements 
SystemViewRowAttributeWalker<CacheView>
         v.accept(16, "evictionFilter", String.class, row.evictionFilter());
         v.accept(17, "evictionPolicyFactory", String.class, 
row.evictionPolicyFactory());
         v.accept(18, "expiryPolicyFactory", String.class, 
row.expiryPolicyFactory());
-        v.accept(19, "interceptor", String.class, row.interceptor());
-        v.acceptBoolean(20, "isCopyOnRead", row.isCopyOnRead());
-        v.acceptBoolean(21, "isEagerTtl", row.isEagerTtl());
-        v.acceptBoolean(22, "isEncryptionEnabled", row.isEncryptionEnabled());
-        v.acceptBoolean(23, "isEventsDisabled", row.isEventsDisabled());
-        v.acceptBoolean(24, "isInvalidate", row.isInvalidate());
-        v.acceptBoolean(25, "isLoadPreviousValue", row.isLoadPreviousValue());
-        v.acceptBoolean(26, "isManagementEnabled", row.isManagementEnabled());
-        v.acceptBoolean(27, "isNearCacheEnabled", row.isNearCacheEnabled());
-        v.acceptBoolean(28, "isOnheapCacheEnabled", 
row.isOnheapCacheEnabled());
-        v.acceptBoolean(29, "isReadFromBackup", row.isReadFromBackup());
-        v.acceptBoolean(30, "isReadThrough", row.isReadThrough());
-        v.acceptBoolean(31, "isSqlEscapeAll", row.isSqlEscapeAll());
-        v.acceptBoolean(32, "isSqlOnheapCacheEnabled", 
row.isSqlOnheapCacheEnabled());
-        v.acceptBoolean(33, "isStatisticsEnabled", row.isStatisticsEnabled());
-        v.acceptBoolean(34, "isStoreKeepBinary", row.isStoreKeepBinary());
-        v.acceptBoolean(35, "isWriteBehindEnabled", 
row.isWriteBehindEnabled());
-        v.acceptBoolean(36, "isWriteThrough", row.isWriteThrough());
-        v.acceptInt(37, "maxConcurrentAsyncOperations", 
row.maxConcurrentAsyncOperations());
-        v.acceptInt(38, "maxQueryIteratorsCount", 
row.maxQueryIteratorsCount());
-        v.accept(39, "nearCacheEvictionPolicyFactory", String.class, 
row.nearCacheEvictionPolicyFactory());
-        v.acceptInt(40, "nearCacheStartSize", row.nearCacheStartSize());
-        v.accept(41, "nodeFilter", String.class, row.nodeFilter());
-        v.accept(42, "partitionLossPolicy", PartitionLossPolicy.class, 
row.partitionLossPolicy());
-        v.acceptInt(43, "queryDetailMetricsSize", 
row.queryDetailMetricsSize());
-        v.acceptInt(44, "queryParallelism", row.queryParallelism());
-        v.acceptInt(45, "rebalanceBatchSize", row.rebalanceBatchSize());
-        v.acceptLong(46, "rebalanceBatchesPrefetchCount", 
row.rebalanceBatchesPrefetchCount());
-        v.acceptLong(47, "rebalanceDelay", row.rebalanceDelay());
-        v.accept(48, "rebalanceMode", CacheRebalanceMode.class, 
row.rebalanceMode());
-        v.acceptInt(49, "rebalanceOrder", row.rebalanceOrder());
-        v.acceptLong(50, "rebalanceThrottle", row.rebalanceThrottle());
-        v.acceptLong(51, "rebalanceTimeout", row.rebalanceTimeout());
-        v.acceptInt(52, "sqlIndexMaxInlineSize", row.sqlIndexMaxInlineSize());
-        v.acceptInt(53, "sqlOnheapCacheMaxSize", row.sqlOnheapCacheMaxSize());
-        v.accept(54, "sqlSchema", String.class, row.sqlSchema());
-        v.accept(55, "topologyValidator", String.class, 
row.topologyValidator());
-        v.acceptInt(56, "writeBehindBatchSize", row.writeBehindBatchSize());
-        v.acceptBoolean(57, "writeBehindCoalescing", 
row.writeBehindCoalescing());
-        v.acceptLong(58, "writeBehindFlushFrequency", 
row.writeBehindFlushFrequency());
-        v.acceptInt(59, "writeBehindFlushSize", row.writeBehindFlushSize());
-        v.acceptInt(60, "writeBehindFlushThreadCount", 
row.writeBehindFlushThreadCount());
-        v.accept(61, "writeSynchronizationMode", 
CacheWriteSynchronizationMode.class, row.writeSynchronizationMode());
+        v.accept(19, "hasExpiringEntries", String.class, 
row.hasExpiringEntries());
+        v.accept(20, "interceptor", String.class, row.interceptor());
+        v.acceptBoolean(21, "isCopyOnRead", row.isCopyOnRead());
+        v.acceptBoolean(22, "isEagerTtl", row.isEagerTtl());
+        v.acceptBoolean(23, "isEncryptionEnabled", row.isEncryptionEnabled());
+        v.acceptBoolean(24, "isEventsDisabled", row.isEventsDisabled());
+        v.acceptBoolean(25, "isInvalidate", row.isInvalidate());
+        v.acceptBoolean(26, "isLoadPreviousValue", row.isLoadPreviousValue());
+        v.acceptBoolean(27, "isManagementEnabled", row.isManagementEnabled());
+        v.acceptBoolean(28, "isNearCacheEnabled", row.isNearCacheEnabled());
+        v.acceptBoolean(29, "isOnheapCacheEnabled", 
row.isOnheapCacheEnabled());
+        v.acceptBoolean(30, "isReadFromBackup", row.isReadFromBackup());
+        v.acceptBoolean(31, "isReadThrough", row.isReadThrough());
+        v.acceptBoolean(32, "isSqlEscapeAll", row.isSqlEscapeAll());
+        v.acceptBoolean(33, "isSqlOnheapCacheEnabled", 
row.isSqlOnheapCacheEnabled());
+        v.acceptBoolean(34, "isStatisticsEnabled", row.isStatisticsEnabled());
+        v.acceptBoolean(35, "isStoreKeepBinary", row.isStoreKeepBinary());
+        v.acceptBoolean(36, "isWriteBehindEnabled", 
row.isWriteBehindEnabled());
+        v.acceptBoolean(37, "isWriteThrough", row.isWriteThrough());
+        v.acceptInt(38, "maxConcurrentAsyncOperations", 
row.maxConcurrentAsyncOperations());
+        v.acceptInt(39, "maxQueryIteratorsCount", 
row.maxQueryIteratorsCount());
+        v.accept(40, "nearCacheEvictionPolicyFactory", String.class, 
row.nearCacheEvictionPolicyFactory());
+        v.acceptInt(41, "nearCacheStartSize", row.nearCacheStartSize());
+        v.accept(42, "nodeFilter", String.class, row.nodeFilter());
+        v.accept(43, "partitionLossPolicy", PartitionLossPolicy.class, 
row.partitionLossPolicy());
+        v.acceptInt(44, "queryDetailMetricsSize", 
row.queryDetailMetricsSize());
+        v.acceptInt(45, "queryParallelism", row.queryParallelism());
+        v.acceptInt(46, "rebalanceBatchSize", row.rebalanceBatchSize());
+        v.acceptLong(47, "rebalanceBatchesPrefetchCount", 
row.rebalanceBatchesPrefetchCount());
+        v.acceptLong(48, "rebalanceDelay", row.rebalanceDelay());
+        v.accept(49, "rebalanceMode", CacheRebalanceMode.class, 
row.rebalanceMode());
+        v.acceptInt(50, "rebalanceOrder", row.rebalanceOrder());
+        v.acceptLong(51, "rebalanceThrottle", row.rebalanceThrottle());
+        v.acceptLong(52, "rebalanceTimeout", row.rebalanceTimeout());
+        v.acceptInt(53, "sqlIndexMaxInlineSize", row.sqlIndexMaxInlineSize());
+        v.acceptInt(54, "sqlOnheapCacheMaxSize", row.sqlOnheapCacheMaxSize());
+        v.accept(55, "sqlSchema", String.class, row.sqlSchema());
+        v.accept(56, "topologyValidator", String.class, 
row.topologyValidator());
+        v.acceptInt(57, "writeBehindBatchSize", row.writeBehindBatchSize());
+        v.acceptBoolean(58, "writeBehindCoalescing", 
row.writeBehindCoalescing());
+        v.acceptLong(59, "writeBehindFlushFrequency", 
row.writeBehindFlushFrequency());
+        v.acceptInt(60, "writeBehindFlushSize", row.writeBehindFlushSize());
+        v.acceptInt(61, "writeBehindFlushThreadCount", 
row.writeBehindFlushThreadCount());
+        v.accept(62, "writeSynchronizationMode", 
CacheWriteSynchronizationMode.class, row.writeSynchronizationMode());
     }
 
     /** {@inheritDoc} */
     @Override public int count() {
-        return 62;
+        return 63;
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
index e10c6ed4544..d437b179769 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManager.java
@@ -170,6 +170,14 @@ public interface IgniteCacheOffheapManager {
      */
     public long expiredSize() throws IgniteCheckedException;
 
+    /**
+     * Checks if the cache has entries pending expire.
+     *
+     * @return {@code True} if there are entries pending expire.
+     * @throws IgniteCheckedException If failed to get number of pending 
entries.
+     */
+    public boolean hasEntriesPendingExpire(int cacheId) throws 
IgniteCheckedException;
+
     /**
      * @param cctx Cache context.
      * @param key Key.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
index f1b0f215335..923eb153bef 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
@@ -1174,6 +1174,22 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
         return pendingEntries != null ? pendingEntries.size() : 0;
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean hasEntriesPendingExpire(int cacheId) throws 
IgniteCheckedException {
+        if (pendingEntries == null)
+            return false;
+
+        if (grp.sharedGroup()) {
+            PendingRow row = new PendingRow(cacheId);
+
+            GridCursor<PendingRow> cursor = pendingEntries.find(row, row, 
PendingEntriesTree.WITHOUT_KEY);
+
+            return cursor.next();
+        }
+        else
+            return !pendingEntries.isEmpty();
+    }
+
     /**
      *
      */
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
index 9643b65c707..5056f063189 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
@@ -1154,6 +1154,16 @@ public class GridCacheOffheapManager extends 
IgniteCacheOffheapManagerImpl imple
         return size;
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean hasEntriesPendingExpire(int cacheId) throws 
IgniteCheckedException {
+        for (CacheDataStore store : cacheDataStores()) {
+            if (((GridCacheDataStore)store).hasEntriesPendingExpire(cacheId))
+                return true;
+        }
+
+        return false;
+    }
+
     /** {@inheritDoc} */
     @Override public void preloadPartition(int partId) throws 
IgniteCheckedException {
         GridDhtLocalPartition locPart = grp.topology().localPartition(partId, 
AffinityTopologyVersion.NONE, false, false);
@@ -2660,6 +2670,29 @@ public class GridCacheOffheapManager extends 
IgniteCacheOffheapManagerImpl imple
             return delegate0 == null ? 0 : pendingTree.size();
         }
 
+        /**
+         * Checks if the cache has entries pending expire.
+         *
+         * @return {@code True} if there are entries pending expire.
+         * @throws IgniteCheckedException If failed to get number of pending 
entries.
+         */
+        public boolean hasEntriesPendingExpire(int cacheId) throws 
IgniteCheckedException {
+            CacheDataStore delegate0 = init0(true);
+
+            if (delegate0 == null)
+                return false;
+
+            if (grp.sharedGroup()) {
+                PendingRow row = new PendingRow(cacheId);
+
+                GridCursor<PendingRow> cur = pendingTree.find(row, row, 
PendingEntriesTree.WITHOUT_KEY);
+
+                return cur.next();
+            }
+            else
+                return !pendingTree.isEmpty();
+        }
+
         /**
          * Try to remove expired entries from data store.
          *
diff --git 
a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheView.java
 
b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheView.java
index 72c663fb3e7..2cc1ca8d655 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheView.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CacheView.java
@@ -17,6 +17,11 @@
 
 package org.apache.ignite.spi.systemview.view;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.cache.configuration.Factory;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
@@ -29,11 +34,13 @@ import 
org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.configuration.TopologyValidator;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.managers.systemview.walker.Order;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.CacheGroupDescriptor;
 import org.apache.ignite.internal.processors.cache.CacheType;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
 import 
org.apache.ignite.internal.processors.cache.version.CacheVersionConflictResolver;
+import org.apache.ignite.internal.util.typedef.internal.S;
 
 import static org.apache.ignite.internal.util.IgniteUtils.toStringSafe;
 
@@ -331,7 +338,78 @@ public class CacheView {
 
     /** @see CacheConfiguration#getExpiryPolicyFactory() */
     public String expiryPolicyFactory() {
-        return 
toStringSafe(cache.cacheConfiguration().getExpiryPolicyFactory());
+        if (cache.cacheConfiguration().getExpiryPolicyFactory() == null)
+            return null;
+
+        ExpiryPolicy expiryPlc = 
(ExpiryPolicy)cache.cacheConfiguration().getExpiryPolicyFactory().create();
+
+        AtomicBoolean first = new AtomicBoolean(true);
+
+        StringBuilder expiryPlcStrBld = new 
StringBuilder(expiryPlc.getClass().getSimpleName());
+
+        appendField(expiryPlcStrBld, "create", 
expiryPlc.getExpiryForCreation(), first);
+        appendField(expiryPlcStrBld, "update", expiryPlc.getExpiryForUpdate(), 
first);
+        appendField(expiryPlcStrBld, "access", expiryPlc.getExpiryForAccess(), 
first);
+
+        if (!first.get())
+            expiryPlcStrBld.append(']');
+
+        return 
S.toString((Class<Factory<?>>)cache.cacheConfiguration().getExpiryPolicyFactory().getClass(),
+            cache.cacheConfiguration().getExpiryPolicyFactory(), "expiryPlc", 
expiryPlcStrBld);
+    }
+
+    /**
+     * @param out {@link StringBuilder} to append to.
+     * @param fieldName create/update/access expiry policy field name.
+     * @param duration {@link Duration} for specified expiry policy field name.
+     * @param first {@link AtomicBoolean} flag indicating whether the field is 
the first in sequence.
+     */
+    private static void appendField(
+        StringBuilder out,
+        String fieldName,
+        Duration duration,
+        AtomicBoolean first
+    ) {
+        if (duration != null) {
+            if (!first.get())
+                out.append(", ");
+            else {
+                out.append(" [");
+                first.compareAndSet(true, false);
+            }
+
+            out.append(fieldName).append('=');
+            appendDuration(out, duration);
+        }
+    }
+
+    /**
+     * Duration representation for specified StringBuilder instance.
+     * @param out {@link StringBuilder} to append to.
+     * @param duration {@link Duration}.
+     */
+    private static void appendDuration(StringBuilder out, Duration duration) {
+        if (duration.isEternal())
+            out.append("ETERNAL");
+        else if (duration.isZero())
+            out.append("ZERO");
+        else
+            out.append(duration.getDurationAmount()).append(' 
').append(duration.getTimeUnit());
+    }
+
+    /** @return {@code Yes} if cache has expired entries, {@code No} 
otherwise. If {@code eagerTtl = true} returns 'Unknown'. */
+    public String hasExpiringEntries() {
+        CacheGroupContext grpCtx = ctx.cache().cacheGroup(cache.groupId());
+
+        if (!cache.cacheConfiguration().isEagerTtl() || grpCtx == null)
+            return "Unknown";
+
+        try {
+            return grpCtx.offheap().hasEntriesPendingExpire(cache.cacheId()) ? 
"Yes" : "No";
+        }
+        catch (IgniteCheckedException e) {
+            return e.getMessage();
+        }
     }
 
     /** @see CacheConfiguration#isSqlEscapeAll() */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewCacheExpiryPolicyTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewCacheExpiryPolicyTest.java
new file mode 100644
index 00000000000..d0bda2428c8
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewCacheExpiryPolicyTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.metric;
+
+import java.util.Arrays;
+import java.util.Collection;
+import javax.cache.configuration.Factory;
+import javax.cache.expiry.AccessedExpiryPolicy;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.EternalExpiryPolicy;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.expiry.ModifiedExpiryPolicy;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import 
org.apache.ignite.internal.processors.platform.cache.expiry.PlatformExpiryPolicyFactory;
+import org.apache.ignite.spi.systemview.view.CacheView;
+import org.apache.ignite.spi.systemview.view.SystemView;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static 
org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHES_VIEW;
+
+/** Tests for {@link CacheView} expiry policy factory representation. */
+@RunWith(Parameterized.class)
+public class SystemViewCacheExpiryPolicyTest extends GridCommonAbstractTest {
+    /** {@link Factory} instances for test with different expiry policy. */
+    private static final Factory[] TTL_FACTORIES = {
+        null,
+        EternalExpiryPolicy.factoryOf(),
+        CreatedExpiryPolicy.factoryOf(new Duration(MILLISECONDS, 100L)),
+        ModifiedExpiryPolicy.factoryOf(new Duration(MILLISECONDS, 5L)),
+        AccessedExpiryPolicy.factoryOf(new Duration(MINUTES, 10L)),
+        new PlatformExpiryPolicyFactory(2, 4, 8),
+        new PlatformExpiryPolicyFactory(1, -2, -1),
+        new PlatformExpiryPolicyFactory(-1, 0, -1),
+        new PlatformExpiryPolicyFactory(0, 1, -1)
+    };
+
+    /** {@link Factory} instance. */
+    @Parameterized.Parameter
+    public Factory<ExpiryPolicy> factory;
+
+    /** Anticipated {@link String} expiry policy factory representation. */
+    @Parameterized.Parameter(1)
+    public String actual;
+
+    /**
+     * @return Test parameters.
+     */
+    @Parameterized.Parameters(name = "factory={0}, actual={1}")
+    public static Collection parameters() {
+        return Arrays.asList(new Object[][] {
+            {TTL_FACTORIES[0], "SingletonFactory 
[expiryPlc=EternalExpiryPolicy [create=ETERNAL]]"},
+            {TTL_FACTORIES[1], "SingletonFactory 
[expiryPlc=EternalExpiryPolicy [create=ETERNAL]]"},
+            {TTL_FACTORIES[2], "SingletonFactory 
[expiryPlc=CreatedExpiryPolicy [create=100 MILLISECONDS]]"},
+            {TTL_FACTORIES[3], "SingletonFactory 
[expiryPlc=ModifiedExpiryPolicy [create=5 MILLISECONDS, update=5 
MILLISECONDS]]"},
+            {TTL_FACTORIES[4], "SingletonFactory 
[expiryPlc=AccessedExpiryPolicy [create=10 MINUTES, access=10 MINUTES]]"},
+            {
+                TTL_FACTORIES[5], "PlatformExpiryPolicyFactory [create=2, 
update=4, access=8," +
+                    " expiryPlc=PlatformExpiryPolicy [create=2 MILLISECONDS, 
update=4 MILLISECONDS, access=8 MILLISECONDS]]"},
+            {
+                TTL_FACTORIES[6], "PlatformExpiryPolicyFactory [create=1, 
update=-2, access=-1," +
+                    " expiryPlc=PlatformExpiryPolicy [create=1 MILLISECONDS, 
access=ETERNAL]]"},
+            {
+                TTL_FACTORIES[7], "PlatformExpiryPolicyFactory [create=-1, 
update=0, access=-1," +
+                    " expiryPlc=PlatformExpiryPolicy [create=ETERNAL, 
update=ZERO, access=ETERNAL]]"},
+            {
+                TTL_FACTORIES[8], "PlatformExpiryPolicyFactory [create=0, 
update=1, access=-1," +
+                    " expiryPlc=PlatformExpiryPolicy [create=ZERO, update=1 
MILLISECONDS, access=ETERNAL]]"}
+        });
+    }
+
+    /**
+     * Test for {@link CacheView} expiry policy factory representation. The 
test initializes the {@link CacheConfiguration}
+     * with custom {@link PlatformExpiryPolicyFactory}. Given different ttl 
input, the test checks the {@link String}
+     * expiry policy factory outcome for {@link 
CacheView#expiryPolicyFactory()}.
+     */
+    @Test
+    public void testCacheViewExpiryPolicy() throws Exception {
+        try (IgniteEx g = startGrid()) {
+            CacheConfiguration<Integer, Integer> ccfg = new 
CacheConfiguration<>();
+            ccfg.setName("cache");
+            ccfg.setExpiryPolicyFactory(factory);
+
+            g.getOrCreateCache(ccfg);
+
+            SystemView<CacheView> caches = 
g.context().systemView().view(CACHES_VIEW);
+
+            for (CacheView row : caches)
+                if ("cache".equals(row.cacheName()))
+                    assertEquals(actual, row.expiryPolicyFactory());
+        }
+    }
+}
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
index fce35b6ae41..ebf2a5388a1 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
@@ -36,6 +36,10 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 import javax.cache.Cache;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.EternalExpiryPolicy;
+import javax.cache.expiry.ModifiedExpiryPolicy;
 import com.google.common.collect.Lists;
 import org.apache.ignite.IgniteAtomicLong;
 import org.apache.ignite.IgniteAtomicReference;
@@ -259,6 +263,112 @@ public class SystemViewSelfTest extends 
GridCommonAbstractTest {
         }
     }
 
+    /** Tests work of {@link SystemView} for cache expiry policy info with 
in-memory configuration. */
+    @Test
+    public void testCacheViewExpiryPolicyWithInMemory() throws Exception {
+        testCacheViewExpiryPolicy(false);
+    }
+
+    /** Tests work of {@link SystemView} for cache expiry policy info with 
persist configuration. */
+    @Test
+    public void testCacheViewExpiryPolicyWithPersist() throws Exception {
+        testCacheViewExpiryPolicy(true);
+    }
+
+    /** Tests work of {@link SystemView} for cache groups expiry policy info. 
*/
+    private void testCacheViewExpiryPolicy(boolean withPersistence) throws 
Exception {
+        try (IgniteEx g = !withPersistence ? startGrid() : 
startGrid(getConfiguration().setDataStorageConfiguration(
+            new DataStorageConfiguration().setDefaultDataRegionConfiguration(
+                new DataRegionConfiguration().setPersistenceEnabled(true)
+            )))) {
+
+            if (withPersistence)
+                g.cluster().state(ClusterState.ACTIVE);
+
+            String eternalCacheName = "eternalCache";
+            String createdCacheName = "createdCache";
+            String eagerTtlCacheName = "eagerTtlCache";
+            String withoutGrpCacheName = "withoutGrpCache";
+            String dfltCacheName = "defaultCache";
+
+            CacheConfiguration<Long, Long> eternalCache = new 
CacheConfiguration<Long, Long>(eternalCacheName)
+                .setGroupName("group1")
+                .setExpiryPolicyFactory(EternalExpiryPolicy.factoryOf());
+
+            CacheConfiguration<Long, Long> createdCache = new 
CacheConfiguration<Long, Long>(createdCacheName)
+                .setGroupName("group2")
+                .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new 
Duration(TimeUnit.MILLISECONDS, 500L)));
+
+            CacheConfiguration<Long, Long> eagerTtlCache = new 
CacheConfiguration<Long, Long>(eagerTtlCacheName)
+                .setGroupName("group2")
+                .setEagerTtl(false)
+                .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new 
Duration(TimeUnit.MILLISECONDS, 500L)));
+
+            CacheConfiguration<Long, Long> withoutGrpCache = new 
CacheConfiguration<Long, Long>(withoutGrpCacheName)
+                .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new 
Duration(TimeUnit.MILLISECONDS, 500L)));
+
+            CacheConfiguration<Long, Long> dfltCache = new 
CacheConfiguration<Long, Long>(dfltCacheName)
+                .setGroupName("group3");
+
+            g.createCache(eternalCache);
+            g.createCache(createdCache);
+            g.createCache(eagerTtlCache);
+            g.createCache(withoutGrpCache);
+            g.createCache(dfltCache);
+
+            SystemView<CacheView> caches = 
g.context().systemView().view(CACHES_VIEW);
+
+            for (CacheView row : caches) {
+                switch (row.cacheName()) {
+                    case "defaultCache":
+                    case "eternalCache":
+                        assertEquals("No", row.hasExpiringEntries());
+
+                        g.cache(row.cacheName()).put(0, 0);
+
+                        assertEquals("No", row.hasExpiringEntries());
+
+                        g.cache(row.cacheName())
+                            .withExpiryPolicy(new CreatedExpiryPolicy(new 
Duration(TimeUnit.MILLISECONDS, 200L)))
+                            .put(1, 1);
+
+                        assertEquals("Yes", row.hasExpiringEntries());
+                        assertTrue(waitForCondition(() -> 
"No".equals(row.hasExpiringEntries()), getTestTimeout()));
+
+                        break;
+
+                    case "withoutGrpCache":
+                    case "createdCache":
+                        assertEquals("No", row.hasExpiringEntries());
+
+                        g.cache(row.cacheName()).put(0, 0);
+
+                        assertEquals("Yes", row.hasExpiringEntries());
+                        assertTrue(waitForCondition(() -> 
"No".equals(row.hasExpiringEntries()), getTestTimeout()));
+
+                        g.cache(row.cacheName())
+                            .withExpiryPolicy(new ModifiedExpiryPolicy(new 
Duration(TimeUnit.MILLISECONDS, 200L)))
+                            .put(1, 1);
+
+                        assertEquals("Yes", row.hasExpiringEntries());
+                        assertTrue(waitForCondition(() -> 
"No".equals(row.hasExpiringEntries()), getTestTimeout()));
+
+                        if (row.cacheName().equals(createdCacheName)) {
+                            g.cache(eagerTtlCacheName).put(2, 2);
+                            assertEquals("No", row.hasExpiringEntries());
+                        }
+
+                        break;
+
+                    case "eagerTtlCache":
+                        assertEquals("Unknown", row.hasExpiringEntries());
+
+                        break;
+                }
+            }
+        }
+    }
+
     /** Tests work of {@link SystemView} for services. */
     @Test
     public void testServices() throws Exception {
diff --git 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java
 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java
index 6c9daabd47d..58ace1eff29 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite13.java
@@ -32,6 +32,7 @@ import 
org.apache.ignite.internal.metric.MetricsConfigurationTest;
 import org.apache.ignite.internal.metric.MetricsSelfTest;
 import org.apache.ignite.internal.metric.ReadMetricsOnNodeStartupTest;
 import org.apache.ignite.internal.metric.SystemMetricsTest;
+import org.apache.ignite.internal.metric.SystemViewCacheExpiryPolicyTest;
 import org.apache.ignite.internal.metric.SystemViewClusterActivationTest;
 import org.apache.ignite.internal.metric.SystemViewComputeJobTest;
 import org.apache.ignite.internal.metric.SystemViewSelfTest;
@@ -86,6 +87,7 @@ public class IgniteCacheTestSuite13 {
         GridTestUtils.addTestIfNeeded(suite, SystemViewSelfTest.class, 
ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, 
SystemViewClusterActivationTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, SystemViewComputeJobTest.class, 
ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, 
SystemViewCacheExpiryPolicyTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, CacheMetricsAddRemoveTest.class, 
ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, JmxExporterSpiTest.class, 
ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, LogExporterSpiTest.class, 
ignoredTests);


Reply via email to