This is an automated email from the ASF dual-hosted git repository.
rpuch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 14e03754680 IGNITE-27358 Add page memory metrics (#7320)
14e03754680 is described below
commit 14e03754680467e4c97cfd98d5233ec0fe242afd
Author: Viacheslav Blinov <[email protected]>
AuthorDate: Tue Dec 30 18:25:27 2025 +0300
IGNITE-27358 Add page memory metrics (#7320)
Co-authored-by: Roman Puchkovskiy <[email protected]>
---
.../pagememory/persistence/PageCacheMetrics.java | 29 +++++++
.../persistence/PersistentPageMemory.java | 66 ++++++++++-----
.../PersistentPageMemoryMetricSource.java | 9 ++
.../persistence/PersistentPageMemoryMetrics.java | 98 +++++++++++++++++++++-
.../MeteredPageReplacementPolicyFactory.java | 77 +++++++++++++++++
.../replacement/AbstractPageReplacementTest.java | 43 +++++++++-
6 files changed, 295 insertions(+), 27 deletions(-)
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageCacheMetrics.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageCacheMetrics.java
new file mode 100644
index 00000000000..8cd31d555e1
--- /dev/null
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageCacheMetrics.java
@@ -0,0 +1,29 @@
+/*
+ * 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.pagememory.persistence;
+
+/** Interface for collecting page cache metrics. */
+public interface PageCacheMetrics {
+ /** Increases the page cache hit metric by one. */
+ void incrementPageCacheHit();
+
+ /** Increases the page cache miss metric by one. */
+ void incrementPageCacheMiss();
+
+ void incrementPageReplacement();
+}
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java
index 6181f9f32e2..21d33ae52e9 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java
@@ -98,6 +98,7 @@ import
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointTi
import
org.apache.ignite.internal.pagememory.persistence.replacement.ClockPageReplacementPolicyFactory;
import
org.apache.ignite.internal.pagememory.persistence.replacement.DelayedDirtyPageWrite;
import
org.apache.ignite.internal.pagememory.persistence.replacement.DelayedPageReplacementTracker;
+import
org.apache.ignite.internal.pagememory.persistence.replacement.MeteredPageReplacementPolicyFactory;
import
org.apache.ignite.internal.pagememory.persistence.replacement.PageReplacementPolicy;
import
org.apache.ignite.internal.pagememory.persistence.replacement.PageReplacementPolicyFactory;
import
org.apache.ignite.internal.pagememory.persistence.replacement.RandomLruPageReplacementPolicyFactory;
@@ -250,27 +251,13 @@ public class PersistentPageMemory implements PageMemory {
sysPageSize = pageSize + PAGE_OVERHEAD;
this.rwLock = rwLock;
+ metrics = new PersistentPageMemoryMetrics(metricSource, this,
dataRegionConfiguration);
ReplacementMode replacementMode =
this.dataRegionConfiguration.replacementMode();
-
- switch (replacementMode) {
- case RANDOM_LRU:
- pageReplacementPolicyFactory = new
RandomLruPageReplacementPolicyFactory();
-
- break;
- case SEGMENTED_LRU:
- pageReplacementPolicyFactory = new
SegmentedLruPageReplacementPolicyFactory();
-
- break;
- case CLOCK:
- pageReplacementPolicyFactory = new
ClockPageReplacementPolicyFactory();
-
- break;
- default:
- throw new IgniteInternalException("Unexpected page replacement
mode: " + replacementMode);
- }
-
- metrics = new PersistentPageMemoryMetrics(metricSource, this,
dataRegionConfiguration);
+ this.pageReplacementPolicyFactory = new
MeteredPageReplacementPolicyFactory(
+ metrics,
+ pickPageReplacementPolicyFactory(replacementMode)
+ );
delayedPageReplacementTracker = new DelayedPageReplacementTracker(
pageSize,
@@ -287,6 +274,19 @@ public class PersistentPageMemory implements PageMemory {
this.writeThrottle = null;
}
+ private static PageReplacementPolicyFactory
pickPageReplacementPolicyFactory(ReplacementMode replacementMode) {
+ switch (replacementMode) {
+ case RANDOM_LRU:
+ return new RandomLruPageReplacementPolicyFactory();
+ case SEGMENTED_LRU:
+ return new SegmentedLruPageReplacementPolicyFactory();
+ case CLOCK:
+ return new ClockPageReplacementPolicyFactory();
+ default:
+ throw new IgniteInternalException("Unexpected page replacement
mode: " + replacementMode);
+ }
+ }
+
/**
* Temporary method to enable throttling in tests.
*
@@ -644,6 +644,8 @@ public class PersistentPageMemory implements PageMemory {
grpId, hexLong(pageId)
);
+ long startTime = System.nanoTime();
+
FullPageId fullId = new FullPageId(pageId, grpId);
Segment seg = segment(grpId, pageId);
@@ -681,6 +683,8 @@ public class PersistentPageMemory implements PageMemory {
if (waitUntilPageIsFullyInitialized) {
waitUntilPageIsFullyInitialized(resPointer);
}
+
+ metrics.recordPageAcquireTime(System.nanoTime() - startTime);
}
seg.writeLock().lock();
@@ -821,6 +825,8 @@ public class PersistentPageMemory implements PageMemory {
headerIsValid(lockedPageAbsPtr, true);
}
}
+
+ metrics.recordPageAcquireTime(System.nanoTime() - startTime);
}
}
@@ -1008,10 +1014,6 @@ public class PersistentPageMemory implements PageMemory {
if (segments != null) {
for (Segment seg : segments) {
- if (seg == null) {
- break;
- }
-
seg.readLock().lock();
try {
@@ -1029,6 +1031,24 @@ public class PersistentPageMemory implements PageMemory {
return total;
}
+ /**
+ * Returns the count of dirty pages across all segments.
+ */
+ public long dirtyPagesCount() {
+ Segment[] segments = this.segments;
+ if (segments == null) {
+ return 0;
+ }
+
+ long total = 0;
+
+ for (Segment seg : segments) {
+ total += seg.dirtyPagesCntr.get();
+ }
+
+ return total;
+ }
+
/**
* Returns total number of acquired pages.
*/
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetricSource.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetricSource.java
index 50f007bd8d6..d467ba7f698 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetricSource.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetricSource.java
@@ -28,6 +28,15 @@ import org.jetbrains.annotations.Nullable;
* Metric source for persistent page memory.
*/
public class PersistentPageMemoryMetricSource implements MetricSource {
+ public static final String PAGES_READ = "PagesRead";
+ public static final String PAGES_WRITTEN = "PagesWritten";
+ public static final String PAGE_REPLACEMENTS = "PageReplacements";
+ public static final String PAGE_CACHE_MISSES = "PageCacheMisses";
+ public static final String PAGE_CACHE_HITS = "PageCacheHits";
+ public static final String DIRTY_PAGES = "DirtyPages";
+ public static final String LOADED_PAGES = "LoadedPages";
+ public static final String PAGE_ACQUIRE_TIME = "PageAcquireTime";
+
private final String name;
/** Metrics map. Only modified in {@code synchronized} context. */
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetrics.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetrics.java
index c3594ee6cf8..8adfad4ca98 100644
---
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetrics.java
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryMetrics.java
@@ -17,17 +17,46 @@
package org.apache.ignite.internal.pagememory.persistence;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.DIRTY_PAGES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.LOADED_PAGES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGES_READ;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGES_WRITTEN;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_ACQUIRE_TIME;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_CACHE_HITS;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_CACHE_MISSES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_REPLACEMENTS;
+
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.internal.metrics.DistributionMetric;
+import org.apache.ignite.internal.metrics.HitRateMetric;
import org.apache.ignite.internal.metrics.IntGauge;
import org.apache.ignite.internal.metrics.LongAdderMetric;
import org.apache.ignite.internal.metrics.LongGauge;
import
org.apache.ignite.internal.pagememory.configuration.PersistentDataRegionConfiguration;
/** Persistent page memory metrics. */
-class PersistentPageMemoryMetrics {
+class PersistentPageMemoryMetrics implements PageCacheMetrics {
+ private static final long[] PAGE_ACQUISITIONS_BOUNDS_NANOS = {
+ 1_000, // 1µs - cache hit
+ 100_000, // 100µs - page cache miss, fast SSD
+ 10_000_000, // 10ms - HDD or slow I/O
+ 100_000_000 // 100ms - very slow I/O or high load
+ };
+
private final LongAdderMetric readPagesFromDisk;
private final LongAdderMetric writePagesToDisk;
+ private final LongAdderMetric pageCacheHitsTotal;
+
+ private final LongAdderMetric pageCacheMisses;
+
+ private final DistributionMetric pageAcquireTime;
+
+ private final HitRateMetric pageCacheHitRate;
+
+ private final LongAdderMetric pageReplacements;
+
PersistentPageMemoryMetrics(
PersistentPageMemoryMetricSource source,
PersistentPageMemory pageMemory,
@@ -53,14 +82,53 @@ class PersistentPageMemoryMetrics {
));
readPagesFromDisk = source.addMetric(new LongAdderMetric(
- "PagesRead",
+ PAGES_READ,
"Number of pages read from disk since the last restart."
));
writePagesToDisk = source.addMetric(new LongAdderMetric(
- "PagesWritten",
+ PAGES_WRITTEN,
"Number of pages written to disk since the last restart."
));
+
+ pageCacheHitsTotal = source.addMetric(new LongAdderMetric(
+ PAGE_CACHE_HITS,
+ "Number of times a page was found in the page cache."
+ ));
+
+ pageCacheMisses = source.addMetric(new LongAdderMetric(
+ PAGE_CACHE_MISSES,
+ "Number of times a page was not found in the page cache and
had to be loaded from disk."
+ ));
+
+ pageAcquireTime = source.addMetric(new DistributionMetric(
+ PAGE_ACQUIRE_TIME,
+ "Distribution of page acquisition time in nanoseconds.",
+ PAGE_ACQUISITIONS_BOUNDS_NANOS
+ ));
+
+ pageCacheHitRate = source.addMetric(new HitRateMetric(
+ "PageCacheHitRate",
+ "Page cache hit rate over the last 5 minutes.",
+ TimeUnit.MINUTES.toMillis(5)
+ ));
+
+ pageReplacements = source.addMetric(new LongAdderMetric(
+ PAGE_REPLACEMENTS,
+ "Number of times a page was replaced (evicted) from the page
cache."
+ ));
+
+ source.addMetric(new LongGauge(
+ LOADED_PAGES,
+ "Current number of pages loaded in memory.",
+ pageMemory::loadedPages
+ ));
+
+ source.addMetric(new LongGauge(
+ DIRTY_PAGES,
+ "Current number of dirty pages in memory.",
+ pageMemory::dirtyPagesCount
+ ));
}
/** Increases the disk page read metric by one. */
@@ -72,4 +140,28 @@ class PersistentPageMemoryMetrics {
public void incrementWriteToDiskMetric() {
writePagesToDisk.increment();
}
+
+ /** Increases the page cache hit metric by one. */
+ @Override
+ public void incrementPageCacheHit() {
+ pageCacheHitsTotal.increment();
+ pageCacheHitRate.increment();
+ }
+
+ /** Increases the page cache miss metric by one. */
+ @Override
+ public void incrementPageCacheMiss() {
+ pageCacheMisses.increment();
+ }
+
+ /** Records a page acquisition time in nanoseconds. */
+ public void recordPageAcquireTime(long nanos) {
+ pageAcquireTime.add(nanos);
+ }
+
+ /** Increases the page replacement metric by one. */
+ @Override
+ public void incrementPageReplacement() {
+ pageReplacements.increment();
+ }
}
diff --git
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/MeteredPageReplacementPolicyFactory.java
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/MeteredPageReplacementPolicyFactory.java
new file mode 100644
index 00000000000..47c925c055b
--- /dev/null
+++
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/replacement/MeteredPageReplacementPolicyFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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.pagememory.persistence.replacement;
+
+import org.apache.ignite.internal.lang.IgniteInternalCheckedException;
+import org.apache.ignite.internal.pagememory.persistence.PageCacheMetrics;
+import
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemory.Segment;
+
+/** A factory that augments page replacement policies with metrics collection.
*/
+public class MeteredPageReplacementPolicyFactory implements
PageReplacementPolicyFactory {
+ private final PageReplacementPolicyFactory delegate;
+ private final PageCacheMetrics metrics;
+
+ public MeteredPageReplacementPolicyFactory(PageCacheMetrics metrics,
PageReplacementPolicyFactory delegate) {
+ this.delegate = delegate;
+ this.metrics = metrics;
+ }
+
+ @Override
+ public long requiredMemory(int pagesCnt) {
+ return delegate.requiredMemory(pagesCnt);
+ }
+
+ @Override
+ public PageReplacementPolicy create(Segment seg, long ptr, int pagesCnt) {
+ return new MeteredPageReplacementPolicy(metrics, delegate.create(seg,
ptr, pagesCnt));
+ }
+
+ private static class MeteredPageReplacementPolicy extends
PageReplacementPolicy {
+ private final PageReplacementPolicy delegate;
+ private final PageCacheMetrics metrics;
+
+ private MeteredPageReplacementPolicy(PageCacheMetrics metrics,
PageReplacementPolicy delegate) {
+ super(delegate.seg);
+ this.metrics = metrics;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public long replace() throws IgniteInternalCheckedException {
+ metrics.incrementPageReplacement();
+ return delegate.replace();
+ }
+
+ @Override
+ public void onHit(long relPtr) {
+ metrics.incrementPageCacheHit();
+ delegate.onHit(relPtr);
+ }
+
+ @Override
+ public void onMiss(long relPtr) {
+ metrics.incrementPageCacheMiss();
+ delegate.onMiss(relPtr);
+ }
+
+ @Override
+ public void onRemove(long relPtr) {
+ delegate.onRemove(relPtr);
+ }
+ }
+}
diff --git
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/replacement/AbstractPageReplacementTest.java
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/replacement/AbstractPageReplacementTest.java
index 93754367275..3cd8b1ae6a1 100644
---
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/replacement/AbstractPageReplacementTest.java
+++
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/replacement/AbstractPageReplacementTest.java
@@ -18,6 +18,13 @@
package org.apache.ignite.internal.pagememory.persistence.replacement;
import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_DATA;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.DIRTY_PAGES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.LOADED_PAGES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGES_READ;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGES_WRITTEN;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_CACHE_HITS;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_CACHE_MISSES;
+import static
org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMetricSource.PAGE_REPLACEMENTS;
import static
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointState.FINISHED;
import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageIndex;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.runAsync;
@@ -28,6 +35,9 @@ import static org.apache.ignite.internal.util.Constants.MiB;
import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -51,6 +61,8 @@ import
org.apache.ignite.internal.configuration.testframework.ConfigurationExten
import org.apache.ignite.internal.failure.FailureManager;
import org.apache.ignite.internal.fileio.RandomAccessFileIoFactory;
import org.apache.ignite.internal.lang.RunnableX;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.apache.ignite.internal.metrics.MetricSet;
import org.apache.ignite.internal.pagememory.DataRegion;
import
org.apache.ignite.internal.pagememory.TestPageIoModule.TestSimpleValuePageIo;
import org.apache.ignite.internal.pagememory.TestPageIoRegistry;
@@ -74,6 +86,7 @@ import
org.apache.ignite.internal.testframework.IgniteAbstractTest;
import org.apache.ignite.internal.testframework.InjectExecutorService;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.OffheapReadWriteLock;
+import org.hamcrest.Matcher;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -109,6 +122,9 @@ public abstract class AbstractPageReplacementTest extends
IgniteAbstractTest {
@InjectExecutorService
private ExecutorService executorService;
+ private PersistentPageMemoryMetricSource metricSource;
+ private MetricSet metricSet;
+
protected abstract ReplacementMode replacementMode();
@BeforeEach
@@ -146,10 +162,12 @@ public abstract class AbstractPageReplacementTest extends
IgniteAbstractTest {
PAGE_SIZE
);
+ metricSource = new PersistentPageMemoryMetricSource("test");
+
pageMemory = new PersistentPageMemory(
PersistentDataRegionConfiguration.builder()
.pageSize(PAGE_SIZE).size(MAX_MEMORY_SIZE).replacementMode(replacementMode()).build(),
- new PersistentPageMemoryMetricSource("test"),
+ metricSource,
ioRegistry,
new long[]{MAX_MEMORY_SIZE},
10 * MiB,
@@ -165,6 +183,7 @@ public abstract class AbstractPageReplacementTest extends
IgniteAbstractTest {
filePageStoreManager.start();
checkpointManager.start();
pageMemory.start();
+ metricSet = metricSource.enable();
createPartitionFilePageStoresIfMissing();
}
@@ -343,6 +362,28 @@ public abstract class AbstractPageReplacementTest extends
IgniteAbstractTest {
verify(deltaFileIoFuture.join()).sync();
}
+ @Test
+ void verifyPageMemoryMetrics() throws Throwable {
+ testPageReplacement();
+
+ assertMetricValue(PAGES_READ, is(0L)); // Since there are no existing
pages on disk.
+ assertMetricValue(PAGES_WRITTEN, is(1L));
+ assertMetricValue(PAGE_REPLACEMENTS, is(1L));
+ assertMetricValue(PAGE_CACHE_MISSES, is(greaterThan(1L)));
+ assertMetricValue(PAGE_CACHE_HITS, is(greaterThan(1L)));
+ assertMetricValue(DIRTY_PAGES, is(greaterThan(1L)));
+ assertMetricValue(LOADED_PAGES, is(greaterThan(1L)));
+ }
+
+ private void assertMetricValue(String metricName, Matcher<Long>
valueMatcher) {
+ LongMetric metric = metricSet.get(metricName);
+ assertThat(metric, is(notNullValue()));
+ assertThat(
+ metric.value(),
+ valueMatcher
+ );
+ }
+
private void createAndFillTestSimpleValuePage(long pageId) throws
Exception {
long page = pageMemory.acquirePage(GROUP_ID, pageId);