/* * 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.processors.igfs; import java.util.HashMap; import java.util.Map; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteFileSystem; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.FileSystemConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper; import org.apache.ignite.igfs.IgfsInputStream; import org.apache.ignite.igfs.IgfsIpcEndpointConfiguration; import org.apache.ignite.igfs.IgfsIpcEndpointType; import org.apache.ignite.igfs.IgfsMetrics; import org.apache.ignite.igfs.IgfsMode; import org.apache.ignite.igfs.IgfsOutputStream; import org.apache.ignite.igfs.IgfsPath; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheMode.REPLICATED; import static org.apache.ignite.igfs.IgfsMode.DUAL_SYNC; import static org.apache.ignite.igfs.IgfsMode.PRIMARY; /** * Test for IGFS metrics. */ public class IgfsMetricsSelfTest extends IgfsCommonAbstractTest { /** Primary IGFS name. */ private static final String IGFS_PRIMARY = "igfs-primary"; /** Primary IGFS name. */ private static final String IGFS_SECONDARY = "igfs-secondary"; /** Secondary file system REST endpoint configuration map. */ private static final IgfsIpcEndpointConfiguration SECONDARY_REST_CFG; /** Test nodes count. */ private static final int NODES_CNT = 3; /** IP finder for the grid with the primary file system. */ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** Primary IGFS instances. */ private static IgniteFileSystem[] igfsPrimary; /** Secondary IGFS instance. */ private static IgfsImpl igfsSecondary; /** Primary file system block size. */ public static final int PRIMARY_BLOCK_SIZE = 512; /** Secondary file system block size. */ public static final int SECONDARY_BLOCK_SIZE = 512; static { SECONDARY_REST_CFG = new IgfsIpcEndpointConfiguration(); SECONDARY_REST_CFG.setType(IgfsIpcEndpointType.TCP); SECONDARY_REST_CFG.setPort(11500); } /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { startSecondary(); startPrimary(); } /** {@inheritDoc} */ @Override protected void afterTestsStopped() throws Exception { stopAllGrids(false); } /** * Start a grid with the primary file system. * * @throws Exception If failed. */ private void startPrimary() throws Exception { igfsPrimary = new IgniteFileSystem[NODES_CNT]; for (int i = 0; i < NODES_CNT; i++) { Ignite g = G.start(primaryConfiguration(i)); igfsPrimary[i] = g.fileSystem(IGFS_PRIMARY); } } /** * Get configuration for a grid with the primary file system. * * @param idx Node index. * @return Configuration. * @throws Exception If failed. */ @SuppressWarnings("unchecked") private IgniteConfiguration primaryConfiguration(int idx) throws Exception { FileSystemConfiguration igfsCfg = new FileSystemConfiguration(); igfsCfg.setName(IGFS_PRIMARY); igfsCfg.setBlockSize(PRIMARY_BLOCK_SIZE); igfsCfg.setDefaultMode(DUAL_SYNC); igfsCfg.setSecondaryFileSystem(igfsSecondary.asSecondary()); Map<String, IgfsMode> pathModes = new HashMap<>(); pathModes.put("/primary", PRIMARY); igfsCfg.setPathModes(pathModes); CacheConfiguration dataCacheCfg = defaultCacheConfiguration(); dataCacheCfg.setCacheMode(PARTITIONED); dataCacheCfg.setNearConfiguration(null); dataCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); dataCacheCfg.setAffinityMapper(new IgfsGroupDataBlocksKeyMapper(128)); dataCacheCfg.setBackups(0); dataCacheCfg.setAtomicityMode(TRANSACTIONAL); CacheConfiguration metaCacheCfg = defaultCacheConfiguration(); metaCacheCfg.setCacheMode(REPLICATED); metaCacheCfg.setNearConfiguration(null); metaCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); metaCacheCfg.setAtomicityMode(TRANSACTIONAL); igfsCfg.setMetaCacheConfiguration(metaCacheCfg); igfsCfg.setDataCacheConfiguration(dataCacheCfg); IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setIgniteInstanceName("grid-" + idx); TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); discoSpi.setIpFinder(IP_FINDER); cfg.setDiscoverySpi(discoSpi); cfg.setFileSystemConfiguration(igfsCfg); cfg.setLocalHost("127.0.0.1"); return cfg; } /** * Start a grid with the secondary file system. * * @throws Exception If failed. */ @SuppressWarnings("unchecked") private void startSecondary() throws Exception { FileSystemConfiguration igfsCfg = new FileSystemConfiguration(); igfsCfg.setName(IGFS_SECONDARY); igfsCfg.setBlockSize(SECONDARY_BLOCK_SIZE); igfsCfg.setDefaultMode(PRIMARY); igfsCfg.setIpcEndpointConfiguration(SECONDARY_REST_CFG); CacheConfiguration dataCacheCfg = defaultCacheConfiguration(); dataCacheCfg.setCacheMode(PARTITIONED); dataCacheCfg.setNearConfiguration(null); dataCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); dataCacheCfg.setAffinityMapper(new IgfsGroupDataBlocksKeyMapper(128)); dataCacheCfg.setBackups(0); dataCacheCfg.setAtomicityMode(TRANSACTIONAL); CacheConfiguration metaCacheCfg = defaultCacheConfiguration(); metaCacheCfg.setCacheMode(REPLICATED); metaCacheCfg.setNearConfiguration(null); metaCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); metaCacheCfg.setAtomicityMode(TRANSACTIONAL); igfsCfg.setMetaCacheConfiguration(metaCacheCfg); igfsCfg.setDataCacheConfiguration(dataCacheCfg); IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setIgniteInstanceName("grid-secondary"); TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); discoSpi.setIpFinder(new TcpDiscoveryVmIpFinder(true)); cfg.setDiscoverySpi(discoSpi); cfg.setFileSystemConfiguration(igfsCfg); cfg.setLocalHost("127.0.0.1"); Ignite g = G.start(cfg); igfsSecondary = (IgfsImpl)g.fileSystem(IGFS_SECONDARY); } /** @throws Exception If failed. */ public void testMetrics() throws Exception { IgniteFileSystem fs = igfsPrimary[0]; assertNotNull(fs); IgfsMetrics m = fs.metrics(); assertNotNull(m); assertEquals(0, m.directoriesCount()); assertEquals(0, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); fs.mkdirs(new IgfsPath("/primary/dir1")); m = fs.metrics(); assertNotNull(m); assertEquals(2, m.directoriesCount()); assertEquals(0, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); fs.mkdirs(new IgfsPath("/primary/dir1/dir2/dir3")); fs.mkdirs(new IgfsPath("/primary/dir4")); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(0, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); IgfsOutputStream out1 = fs.create(new IgfsPath("/primary/dir1/file1"), false); IgfsOutputStream out2 = fs.create(new IgfsPath("/primary/dir1/file2"), false); IgfsOutputStream out3 = fs.create(new IgfsPath("/primary/dir1/dir2/file"), false); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(3, m.filesOpenedForWrite()); out1.write(new byte[10]); out2.write(new byte[20]); out3.write(new byte[30]); out1.close(); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(2, m.filesOpenedForWrite()); out2.close(); out3.close(); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); IgfsOutputStream out = fs.append(new IgfsPath("/primary/dir1/file1"), false); out.write(new byte[20]); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(1, m.filesOpenedForWrite()); out.write(new byte[20]); out.close(); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); IgfsInputStream in1 = fs.open(new IgfsPath("/primary/dir1/file1")); IgfsInputStream in2 = fs.open(new IgfsPath("/primary/dir1/file2")); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(2, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); in1.close(); in2.close(); m = fs.metrics(); assertNotNull(m); assertEquals(5, m.directoriesCount()); assertEquals(3, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); fs.delete(new IgfsPath("/primary/dir1/file1"), false); fs.delete(new IgfsPath("/primary/dir1/dir2"), true); m = fs.metrics(); assertNotNull(m); assertEquals(3, m.directoriesCount()); assertEquals(1, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); fs.clear(); m = fs.metrics(); assertNotNull(m); assertEquals(0, m.directoriesCount()); assertEquals(0, m.filesCount()); assertEquals(0, m.filesOpenedForRead()); assertEquals(0, m.filesOpenedForWrite()); } /** @throws Exception If failed. */ public void testMultipleClose() throws Exception { IgniteFileSystem fs = igfsPrimary[0]; IgfsOutputStream out = fs.create(new IgfsPath("/primary/file"), false); out.close(); out.close(); IgfsInputStream in = fs.open(new IgfsPath("/primary/file")); in.close(); in.close(); IgfsMetrics m = fs.metrics(); assertEquals(0, m.filesOpenedForWrite()); assertEquals(0, m.filesOpenedForRead()); } /** * Test block metrics. * * @throws Exception If failed. */ @SuppressWarnings({"ResultOfMethodCallIgnored", "ConstantConditions"}) public void testBlockMetrics() throws Exception { IgfsEx igfs = (IgfsEx)igfsPrimary[0]; IgfsPath fileRemote = new IgfsPath("/fileRemote"); IgfsPath file1 = new IgfsPath("/primary/file1"); IgfsPath file2 = new IgfsPath("/primary/file2"); // Create remote file and write some data to it. IgfsOutputStream out = igfsSecondary.create(fileRemote, 256, true, null, 1, 256, null); int rmtBlockSize = igfsSecondary.info(fileRemote).blockSize(); out.write(new byte[rmtBlockSize]); out.close(); // Start metrics measuring. IgfsMetrics initMetrics = igfs.metrics(); // Create empty file. igfs.create(file1, 256, true, null, 1, 256, null).close(); int blockSize = igfs.info(file1).blockSize(); checkBlockMetrics(initMetrics, igfs.metrics(), 0, 0, 0, 0, 0, 0); // Write two blocks to the file. IgfsOutputStream os = igfs.append(file1, false); os.write(new byte[blockSize * 2]); os.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 0, 0, 0, 2, 0, blockSize * 2); // Write one more file (one block). os = igfs.create(file2, 256, true, null, 1, 256, null); os.write(new byte[blockSize]); os.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 0, 0, 0, 3, 0, blockSize * 3); // Read data from the first file. IgfsInputStream is = igfs.open(file1); is.readFully(0, new byte[blockSize * 2]); is.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 2, 0, blockSize * 2, 3, 0, blockSize * 3); // Read data from the second file with hits. is = igfs.open(file2); is.read(new byte[blockSize]); is.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 3, 0, blockSize * 3, 3, 0, blockSize * 3); // Clear the first file. igfs.create(file1, true).close(); checkBlockMetrics(initMetrics, igfs.metrics(), 3, 0, blockSize * 3, 3, 0, blockSize * 3); // Delete the second file. igfs.delete(file2, false); checkBlockMetrics(initMetrics, igfs.metrics(), 3, 0, blockSize * 3, 3, 0, blockSize * 3); // Read remote file. is = igfs.open(fileRemote); is.read(new byte[rmtBlockSize]); is.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 4, 1, blockSize * 3 + rmtBlockSize, 3, 0, blockSize * 3); // Lets wait for blocks will be placed to cache U.sleep(300); // Read remote file again. is = igfs.open(fileRemote); is.read(new byte[rmtBlockSize]); is.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 5, 1, blockSize * 3 + rmtBlockSize * 2, 3, 0, blockSize * 3); IgfsMetrics metrics = igfs.metrics(); assert metrics.secondarySpaceSize() == rmtBlockSize; // Write some data to the file working in DUAL mode. os = igfs.append(fileRemote, false); os.write(new byte[rmtBlockSize]); os.close(); // Additional block read here due to file ending synchronization. checkBlockMetrics(initMetrics, igfs.metrics(), 5, 1, blockSize * 3 + rmtBlockSize * 2, 4, 1, blockSize * 3 + rmtBlockSize); metrics = igfs.metrics(); assert metrics.secondarySpaceSize() == rmtBlockSize * 2; igfs.delete(fileRemote, false); U.sleep(300); assert igfs.metrics().secondarySpaceSize() == 0; // Write partial block to the first file. os = igfs.append(file1, false); os.write(new byte[blockSize / 2]); os.close(); checkBlockMetrics(initMetrics, igfs.metrics(), 5, 1, blockSize * 3 + rmtBlockSize * 2, 5, 1, blockSize * 7 / 2 + rmtBlockSize); igfs.resetMetrics(); metrics = igfs.metrics(); assert metrics.blocksReadTotal() == 0; assert metrics.blocksReadRemote() == 0; assert metrics.blocksWrittenTotal() == 0; assert metrics.blocksWrittenRemote() == 0; assert metrics.bytesRead() == 0; assert metrics.bytesReadTime() == 0; assert metrics.bytesWritten() == 0; assert metrics.bytesWriteTime() == 0; } /** * Ensure overall block-related metrics correctness. * * @param initMetrics Initial metrics. * @param metrics Metrics to check. * @param blocksRead Blocks read remote. * @param blocksReadRemote Blocks read remote. * @param bytesRead Bytes read. * @param blocksWrite Blocks write. * @param blocksWriteRemote Blocks write remote. * @param bytesWrite Bytes write. * @throws Exception If failed. */ private void checkBlockMetrics(IgfsMetrics initMetrics, IgfsMetrics metrics, long blocksRead, long blocksReadRemote, long bytesRead, long blocksWrite, long blocksWriteRemote, long bytesWrite) throws Exception { assert metrics != null; assertEquals(blocksRead, metrics.blocksReadTotal() - initMetrics.blocksReadTotal()); assertEquals(blocksReadRemote, metrics.blocksReadRemote() - initMetrics.blocksReadRemote()); assertEquals(bytesRead, metrics.bytesRead() - initMetrics.bytesRead()); assertEquals(blocksWrite, metrics.blocksWrittenTotal() - initMetrics.blocksWrittenTotal()); assertEquals(blocksWriteRemote, metrics.blocksWrittenRemote() - initMetrics.blocksWrittenRemote()); assertEquals(bytesWrite, metrics.bytesWritten() - initMetrics.bytesWritten()); } }