| /* |
| * 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.cache; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| import java.util.stream.Collectors; |
| import java.util.stream.IntStream; |
| import java.util.stream.Stream; |
| import org.apache.ignite.cache.query.SqlFieldsQuery; |
| import org.apache.ignite.cluster.ClusterState; |
| import org.apache.ignite.configuration.DataRegionConfiguration; |
| import org.apache.ignite.configuration.DataStorageConfiguration; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.failure.StopNodeOrHaltFailureHandler; |
| import org.apache.ignite.internal.IgniteEx; |
| import org.apache.ignite.internal.util.typedef.F; |
| import org.apache.ignite.testframework.ListeningTestLogger; |
| import org.apache.ignite.testframework.LogListener; |
| import org.apache.ignite.testframework.junits.WithSystemProperty; |
| import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; |
| import org.junit.Test; |
| |
| import static java.lang.String.format; |
| import static org.apache.ignite.IgniteSystemProperties.IGNITE_MAX_INDEX_PAYLOAD_SIZE; |
| import static org.apache.ignite.internal.processors.query.GridQueryProcessor.INLINE_SIZES_DIFFER_WARN_MSG_FORMAT; |
| |
| /** |
| * Checks that node prints warn message on join node, if indexes inlize size are different on the nodes. |
| */ |
| @WithSystemProperty(key = IGNITE_MAX_INDEX_PAYLOAD_SIZE, value = "1") |
| public class CheckIndexesInlineSizeOnNodeJoinMultiJvmTest extends GridCommonAbstractTest { |
| /** */ |
| private static final String STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| |
| /** */ |
| private static final String INDEXES_WARN_MSG_FORMAT = |
| "PUBLIC#TEST_TABLE#L_IDX(%d,%d),PUBLIC#TEST_TABLE#S1_IDX(%d,%d),PUBLIC#TEST_TABLE#I_IDX(%d,%d)"; |
| |
| /** Nodes count. */ |
| private static final int NODES_CNT = 3; |
| |
| /** Max payload inline index size for local node. */ |
| private static final int INITIAL_PAYLOAD_SIZE = 1; |
| |
| /** */ |
| private ListeningTestLogger testLog; |
| |
| /** Max payload inline index size. */ |
| private int payloadSize; |
| |
| /** */ |
| private UUID nodeId; |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { |
| IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName) |
| .setConsistentId(igniteInstanceName) |
| .setFailureHandler(new StopNodeOrHaltFailureHandler()) |
| .setDataStorageConfiguration(new DataStorageConfiguration() |
| .setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true)) |
| ); |
| |
| if (!isRemoteJvm(igniteInstanceName)) |
| cfg.setGridLogger(testLog); |
| |
| if (nodeId != null) |
| cfg.setNodeId(nodeId); |
| |
| return cfg; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTest() throws Exception { |
| super.beforeTest(); |
| |
| stopAllGrids(); |
| |
| cleanPersistenceDir(); |
| |
| assertEquals(INITIAL_PAYLOAD_SIZE, Integer.parseInt(System.getProperty(IGNITE_MAX_INDEX_PAYLOAD_SIZE))); |
| |
| testLog = new ListeningTestLogger(log); |
| |
| startGrids(NODES_CNT).cluster().state(ClusterState.ACTIVE); |
| |
| for (Map.Entry<String, Object[]> entry : getSqlStatements().entrySet()) |
| executeSql(grid(0), entry.getKey(), entry.getValue()); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void afterTest() throws Exception { |
| stopAllGrids(); |
| |
| cleanPersistenceDir(); |
| |
| super.afterTest(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected boolean isMultiJvm() { |
| return true; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected List<String> additionalRemoteJvmArgs() { |
| List<String> args = super.additionalRemoteJvmArgs(); |
| |
| args.add("-D" + IGNITE_MAX_INDEX_PAYLOAD_SIZE + "=" + payloadSize); |
| |
| return args; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteEx startGrid(int idx) throws Exception { |
| payloadSize = getMaxPayloadSize(idx); |
| |
| return super.startGrid(idx); |
| } |
| |
| /** |
| * Checks that warn messages are presented in the logs on joining node. |
| * |
| * @throws Exception If something goes wrong. |
| */ |
| @Test |
| public void testWarnOnJoiningNode() throws Exception { |
| performTestScenario(0); |
| } |
| |
| /** |
| * Checks that warn messages are presented in the logs on the nodes in cluster. |
| * |
| * @throws Exception If something goes wrong. |
| */ |
| @Test |
| public void testWarnOnNodeInCluster() throws Exception { |
| performTestScenario(1); |
| } |
| |
| /** |
| * Restarts node with given index and check messages in the log after node restart. |
| * |
| * @param restartNodeIdx Index of restarting node. |
| * @throws Exception If something goes wrong. |
| */ |
| private void performTestScenario(int restartNodeIdx) throws Exception { |
| assertTrue("Wrong restart node index: " + restartNodeIdx, restartNodeIdx >= 0 && restartNodeIdx < NODES_CNT); |
| |
| Map<Integer, UUID> nodeIdxToNodeId = |
| IntStream.range(0, NODES_CNT).boxed().collect(Collectors.toMap(i -> i, i -> grid(i).localNode().id())); |
| |
| stopGrid(restartNodeIdx); |
| |
| nodeId = UUID.randomUUID(); |
| |
| nodeIdxToNodeId.put(restartNodeIdx, nodeId); |
| |
| Collection<LogListener> listeners = registerListeners(restartNodeIdx, nodeIdxToNodeId); |
| |
| assertFalse(F.isEmpty(listeners)); |
| |
| startGrid(restartNodeIdx); |
| |
| awaitPartitionMapExchange(); |
| |
| for (LogListener listener : listeners) |
| assertTrue(listener.toString(), listener.check()); |
| } |
| |
| /** */ |
| private Collection<LogListener> registerListeners(int restartNodeIdx, Map<Integer, UUID> nodeIdxToNodeId) { |
| List<String> msgs = new ArrayList<>(NODES_CNT - 1); |
| |
| int payloadSize = getMaxPayloadSize(restartNodeIdx); |
| |
| if (restartNodeIdx == 0) { |
| for (Integer idx : nodeIdxToNodeId.keySet()) { |
| if (idx != 0) |
| msgs.add(generateIndexesWarnMessage(nodeIdxToNodeId.get(idx), payloadSize, getMaxPayloadSize(idx))); |
| } |
| } |
| else |
| msgs.add(generateIndexesWarnMessage(nodeIdxToNodeId.get(restartNodeIdx), getMaxPayloadSize(0), payloadSize)); |
| |
| Collection<LogListener> listeners = msgs.stream().map(m -> LogListener.matches(m).build()).collect(Collectors.toList()); |
| |
| listeners.forEach(l -> testLog.registerListener(l)); |
| |
| return listeners; |
| } |
| |
| /** */ |
| private String generateIndexesWarnMessage(UUID nodeId, int payloadSize1, int payloadSize2) { |
| String indexesInfo = format( |
| INDEXES_WARN_MSG_FORMAT, |
| payloadSize1, |
| payloadSize2, |
| payloadSize1, |
| payloadSize2, |
| payloadSize1, |
| payloadSize2 |
| ); |
| |
| return format(INLINE_SIZES_DIFFER_WARN_MSG_FORMAT, nodeId, indexesInfo); |
| } |
| |
| /** */ |
| private int getMaxPayloadSize(int nodeId) { |
| return INITIAL_PAYLOAD_SIZE + nodeId; |
| } |
| |
| /** */ |
| private static List<List<?>> executeSql(IgniteEx node, String stmt, Object... args) { |
| return node.context().query().querySqlFields(new SqlFieldsQuery(stmt).setArgs(args), true).getAll(); |
| } |
| |
| /** */ |
| public static Map<String, Object[]> getSqlStatements() { |
| Object[] EMPTY = new Object[0]; |
| |
| Map<String, Object[]> stmts = new LinkedHashMap<>(); |
| |
| stmts.put("CREATE TABLE TEST_TABLE (i INT, l LONG, s0 VARCHAR, s1 VARCHAR, PRIMARY KEY (i, s0)) WITH \"backups=1\"", EMPTY); |
| |
| for (int i = 0; i < 10; i++) |
| stmts.put("INSERT INTO TEST_TABLE (i, l, s0, s1) VALUES (?, ?, ?, ?)", Stream.of(i, i * i, STR + i, STR + i * i).toArray()); |
| |
| stmts.put("CREATE INDEX i_idx ON TEST_TABLE(i)", EMPTY); |
| stmts.put("CREATE INDEX l_idx ON TEST_TABLE(l)", EMPTY); |
| stmts.put("CREATE INDEX s0_idx ON TEST_TABLE(s0) INLINE_SIZE 10", EMPTY); |
| stmts.put("CREATE INDEX s1_idx ON TEST_TABLE(s1)", EMPTY); |
| |
| return stmts; |
| } |
| } |