This is an automated email from the ASF dual-hosted git repository. tkalkirill pushed a commit to branch ignite-26180 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 289e9e1ba44e3609e934d3b1d81f4237d4609289 Author: Kirill Tkalenko <[email protected]> AuthorDate: Fri Oct 3 16:29:27 2025 +0300 IGNITE-26180 wip --- .../persistence/store/FilePageStore.java | 18 ++++ .../persistence/store/GroupPageStoresMap.java | 9 +- .../persistence/store/FilePageStoreTest.java | 23 +++++ .../PersistentPageMemoryStorageEngine.java | 7 ++ .../PersistentPageMemoryStorageMetricSource.java | 85 +++++++++++++++ .../PersistentPageMemoryStorageMetrics.java | 51 +++++++++ .../PersistentPageMemoryStorageMetricsTest.java | 114 +++++++++++++++++++++ 7 files changed, 305 insertions(+), 2 deletions(-) diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStore.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStore.java index 1e91dfb4b05..867e62a1f16 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStore.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStore.java @@ -252,6 +252,24 @@ public class FilePageStore implements PageStore { return filePageStoreIo.size(); } + /** + * Returns full size of the page store and its delta files in bytes. + * + * <p>May differ from {@link #pages} * {@link FilePageStoreIo#pageSize()} due to delayed writes or due to other implementation specific + * details. + * + * @throws IgniteInternalCheckedException If an I/O error occurs. + */ + public long fullSize() throws IgniteInternalCheckedException { + long size = filePageStoreIo.size(); + + for (DeltaFilePageStoreIo deltaFilePageStoreIo : deltaFilePageStoreIos) { + size += deltaFilePageStoreIo.size(); + } + + return size; + } + /** * Returns file page store path. */ diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java index 0554d47378c..a177d51b238 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java @@ -119,9 +119,14 @@ public class GroupPageStoresMap<T extends PageStore> { private final T pageStore; + /** Constructor. */ + public GroupPartitionPageStore(GroupPartitionId groupPartitionId, T pageStore) { + this.groupPartitionId = groupPartitionId; + this.pageStore = pageStore; + } + private GroupPartitionPageStore(Map.Entry<GroupPartitionId, T> entry) { - this.groupPartitionId = entry.getKey(); - this.pageStore = entry.getValue(); + this(entry.getKey(), entry.getValue()); } /** diff --git a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreTest.java b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreTest.java index ce89c917505..f78b22335f6 100644 --- a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreTest.java +++ b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreTest.java @@ -520,6 +520,29 @@ public class FilePageStoreTest extends BaseIgniteAbstractTest { } } + @Test + void testFullSize() throws Exception { + DeltaFilePageStoreIo deltaFile0 = mock(DeltaFilePageStoreIo.class); + DeltaFilePageStoreIo deltaFile1 = mock(DeltaFilePageStoreIo.class); + + when(deltaFile0.size()).thenReturn(100L); + when(deltaFile1.size()).thenReturn(200L); + + try (FilePageStore filePageStore = createFilePageStore(workDir.resolve("test"), deltaFile0, deltaFile1)) { + assertEquals(300L, filePageStore.fullSize()); + + filePageStore.ensure(); + + assertEquals(300L + PAGE_SIZE, filePageStore.fullSize()); + + long pageId0 = createDataPageId(filePageStore::allocatePage); + + filePageStore.write(pageId0, createPageByteBuffer(pageId0, PAGE_SIZE)); + + assertEquals(300L + PAGE_SIZE * 2, filePageStore.fullSize()); + } + } + private static FilePageStore createFilePageStore(Path filePath) { return createFilePageStore(filePath, new FilePageStoreHeader(VERSION_1, PAGE_SIZE)); } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageEngine.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageEngine.java index 194e5dd22c5..c6173b2cbf2 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageEngine.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageEngine.java @@ -269,8 +269,15 @@ public class PersistentPageMemoryStorageEngine extends AbstractPageMemoryStorage destructionExecutor = executor; + var storageMetricSource = new PersistentPageMemoryStorageMetricSource("storage." + ENGINE_NAME); + + PersistentPageMemoryStorageMetrics.initMetrics(storageMetricSource, filePageStoreManager); + metricManager.registerSource(checkpointMetricSource); + metricManager.registerSource(storageMetricSource); + metricManager.enable(checkpointMetricSource); + metricManager.enable(storageMetricSource); } /** Creates a checkpoint configuration based on the provided {@link PageMemoryCheckpointConfiguration}. */ diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricSource.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricSource.java new file mode 100644 index 00000000000..0d813d0af98 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricSource.java @@ -0,0 +1,85 @@ +/* + * 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.storage.pagememory; + +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.internal.metrics.Metric; +import org.apache.ignite.internal.metrics.MetricSet; +import org.apache.ignite.internal.metrics.MetricSource; +import org.jetbrains.annotations.Nullable; + +/** Persistent page memory storage metric source. */ +class PersistentPageMemoryStorageMetricSource implements MetricSource { + private final String name; + + /** Metrics map. Only modified in {@code synchronized} context. */ + private final Map<String, Metric> metrics = new HashMap<>(); + + /** Enabled flag. Only modified in {@code synchronized} context. */ + private boolean enabled; + + /** + * Constructor. + * + * @param name Metric set name. + */ + PersistentPageMemoryStorageMetricSource(String name) { + this.name = name; + } + + @Override + public String name() { + return name; + } + + @Override + public @Nullable String group() { + return "storage"; + } + + /** Adds metric to the source. */ + synchronized <T extends Metric> T addMetric(T metric) { + assert !enabled : "Cannot add metrics when source is enabled"; + + metrics.put(metric.name(), metric); + + return metric; + } + + @Override + public synchronized @Nullable MetricSet enable() { + if (enabled) { + return null; + } + + enabled = true; + + return new MetricSet(name, description(), group(), Map.copyOf(metrics)); + } + + @Override + public synchronized void disable() { + enabled = false; + } + + @Override + public synchronized boolean enabled() { + return enabled; + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetrics.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetrics.java new file mode 100644 index 00000000000..852815376a8 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetrics.java @@ -0,0 +1,51 @@ +/* + * 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.storage.pagememory; + +import org.apache.ignite.internal.lang.IgniteInternalCheckedException; +import org.apache.ignite.internal.metrics.LongGauge; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStore; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; +import org.apache.ignite.internal.pagememory.persistence.store.GroupPageStoresMap.GroupPartitionPageStore; + +/** Persistent page memory storage metrics. */ +class PersistentPageMemoryStorageMetrics { + /** Initializes metrics in the given metric source. */ + static void initMetrics( + PersistentPageMemoryStorageMetricSource source, + FilePageStoreManager filePageStoreManager + ) { + source.addMetric(new LongGauge( + "StorageSize", + "Size of the entire storage in bytes.", + () -> storageSize(filePageStoreManager) + )); + } + + private static long storageSize(FilePageStoreManager filePageStoreManager) { + return filePageStoreManager.allPageStores().mapToLong(PersistentPageMemoryStorageMetrics::fullSize).sum(); + } + + private static long fullSize(GroupPartitionPageStore<FilePageStore> pageStore) { + try { + return pageStore.pageStore().fullSize(); + } catch (IgniteInternalCheckedException e) { + return 0; + } + } +} diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricsTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricsTest.java new file mode 100644 index 00000000000..434dce47e91 --- /dev/null +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryStorageMetricsTest.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.storage.pagememory; + +import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.stream.Stream; +import org.apache.ignite.internal.lang.IgniteInternalCheckedException; +import org.apache.ignite.internal.manager.ComponentContext; +import org.apache.ignite.internal.metrics.Metric; +import org.apache.ignite.internal.metrics.MetricManager; +import org.apache.ignite.internal.metrics.MetricSet; +import org.apache.ignite.internal.metrics.TestMetricManager; +import org.apache.ignite.internal.pagememory.persistence.GroupPartitionId; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStore; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; +import org.apache.ignite.internal.pagememory.persistence.store.GroupPageStoresMap.GroupPartitionPageStore; +import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** For {@link PersistentPageMemoryStorageMetrics} testing. */ +public class PersistentPageMemoryStorageMetricsTest extends BaseIgniteAbstractTest { + private final MetricManager metricManager = new TestMetricManager(); + + private final PersistentPageMemoryStorageMetricSource metricSource = new PersistentPageMemoryStorageMetricSource("test"); + + private final FilePageStoreManager filePageStoreManager = mock(FilePageStoreManager.class); + + @BeforeEach + void setUp() { + PersistentPageMemoryStorageMetrics.initMetrics(metricSource, filePageStoreManager); + + metricManager.registerSource(metricSource); + metricManager.enable(metricSource); + + assertThat(metricManager.startAsync(new ComponentContext()), willCompleteSuccessfully()); + } + + @AfterEach + void tearDown() { + metricManager.beforeNodeStop(); + + assertThat(metricManager.stopAsync(new ComponentContext()), willCompleteSuccessfully()); + } + + @Test + void testStorageSize() throws Exception { + checkMetricValue("StorageSize", "0"); + + setAllPageStores( + pageStore(new GroupPartitionId(1, 1), 100L), + pageStore(new GroupPartitionId(1, 2), 200L), + pageStoreWithException(new GroupPartitionId(2, 1)) + ); + + checkMetricValue("StorageSize", "300"); + } + + @SafeVarargs + private void setAllPageStores(GroupPartitionPageStore<FilePageStore>... pageStores) { + Stream<GroupPartitionPageStore<FilePageStore>> stream = Arrays.stream(pageStores); + + when(filePageStoreManager.allPageStores()).thenReturn(stream); + } + + private static GroupPartitionPageStore<FilePageStore> pageStore(GroupPartitionId groupPartitionId, long size) throws Exception { + FilePageStore pageStore = mock(FilePageStore.class); + + when(pageStore.fullSize()).thenReturn(size); + + return new GroupPartitionPageStore<>(groupPartitionId, pageStore); + } + + private static GroupPartitionPageStore<FilePageStore> pageStoreWithException(GroupPartitionId groupPartitionId) throws Exception { + FilePageStore pageStore = mock(FilePageStore.class); + + when(pageStore.fullSize()).thenThrow(IgniteInternalCheckedException.class); + + return new GroupPartitionPageStore<>(groupPartitionId, pageStore); + } + + private void checkMetricValue(String metricName, String exp) { + MetricSet metricSet = metricManager.metricSnapshot().metrics().get(metricSource.name()); + + Metric metric = metricSet.get(metricName); + + assertNotNull(metric, metricName); + + assertEquals(exp, metric.getValueAsString(), metricName); + } +}
