blob: b590371e67e6e9300ad1abbbbf867ce0858190e9 [file] [log] [blame]
/*
* 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.example.rebalance;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgnitionManager;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.internal.schema.configuration.SchemaConfigurationConverter;
import org.apache.ignite.schema.SchemaBuilders;
import org.apache.ignite.schema.definition.ColumnType;
import org.apache.ignite.schema.definition.TableDefinition;
import org.apache.ignite.table.KeyValueView;
import org.apache.ignite.table.Tuple;
/**
* This example demonstrates the data rebalance process.
* <p>
* The example emulates the basic scenario when one starts a three-node topology,
* inserts some data, and then scales out by adding two more nodes. After the
* topology is changed, the data is rebalanced and verified for correctness.
* <p>
* To run the example, do the following:
* <ol>
* <li>Import the examples project into you IDE.</li>
* <li>
* Start <b>two</b> nodes using the CLI tool:<br>
* {@code ignite node start --config=$IGNITE_HOME/examples/config/ignite-config.json my-first-node}<br>
* {@code ignite node start --config=$IGNITE_HOME/examples/config/ignite-config.json my-second-node}
* </li>
* <li>Run the example in the IDE.</li>
* <li>
* When requested, start another two nodes using the CLI tool:
* {@code ignite node start --config=$IGNITE_HOME/examples/config/ignite-config.json my-first-additional-node}<br>
* {@code ignite node start --config=$IGNITE_HOME/examples/config/ignite-config.json my-second-additional-node}
* </li>
* <li>Press {@code Enter} to resume the example.</li>
* </ol>
*/
public class RebalanceExample {
public static void main(String[] args) throws Exception {
//--------------------------------------------------------------------------------------
//
// Starting a server node.
//
// NOTE: An embedded server node is only needed to invoke the 'createTable' API.
// In the future releases, this API will be available on the client,
// eliminating the need to start an embedded server node in this example.
//
//--------------------------------------------------------------------------------------
System.out.println("Starting a server node... Logging to file: example-node.log");
System.setProperty("java.util.logging.config.file", "config/java.util.logging.properties");
try (Ignite server = IgnitionManager.start(
"example-node",
Files.readString(Path.of("config", "ignite-config.json")),
Path.of("work")
)) {
//--------------------------------------------------------------------------------------
//
// Creating a table. The API call below is the equivalent of the following DDL:
//
// CREATE TABLE rebalance (
// key INT PRIMARY KEY,
// value VARCHAR
// )
//
//--------------------------------------------------------------------------------------
System.out.println("\nCreating a table...");
TableDefinition tableDef = SchemaBuilders.tableBuilder("PUBLIC", "rebalance")
.columns(
SchemaBuilders.column("key", ColumnType.INT32).asNonNull().build(),
SchemaBuilders.column("value", ColumnType.string()).asNullable().build()
)
.withPrimaryKey("key")
.build();
server.tables().createTable(tableDef.canonicalName(), tableChange ->
SchemaConfigurationConverter.convert(tableDef, tableChange)
.changeReplicas(5)
.changePartitions(1)
);
//--------------------------------------------------------------------------------------
//
// Creating a client to connect to the cluster.
//
//--------------------------------------------------------------------------------------
System.out.println("\nConnecting to server...");
try (IgniteClient client = IgniteClient.builder()
.addresses("127.0.0.1:10800")
.build()
) {
KeyValueView<Tuple, Tuple> kvView = client.tables().table("PUBLIC.rebalance").keyValueView();
//--------------------------------------------------------------------------------------
//
// Inserting several key-value pairs into the table.
//
//--------------------------------------------------------------------------------------
System.out.println("\nInserting key-value pairs...");
for (int i = 0; i < 10; i++) {
Tuple key = Tuple.create().set("key", i);
Tuple value = Tuple.create().set("value", "test_" + i);
kvView.put(key, value);
}
//--------------------------------------------------------------------------------------
//
// Retrieving the newly inserted data.
//
//--------------------------------------------------------------------------------------
System.out.println("\nRetrieved key-value pairs:");
for (int i = 0; i < 10; i++) {
Tuple key = Tuple.create().set("key", i);
Tuple value = kvView.get(key);
System.out.println(" " + i + " -> " + value.stringValue("value"));
}
//--------------------------------------------------------------------------------------
//
// Scaling out by adding two more nodes into the topology.
//
//--------------------------------------------------------------------------------------
System.out.println("\n" +
"Run the following commands using the CLI tool to start two more nodes, and then press 'Enter' to continue...\n" +
" ignite node start --config=examples/config/ignite-config.json my-first-additional-node\n" +
" ignite node start --config=examples/config/ignite-config.json my-second-additional-node");
System.in.read();
//--------------------------------------------------------------------------------------
//
// Updating baseline to initiate the data rebalancing process.
//
// New topology includes the following five nodes:
// 1. 'my-first-node' -- the first node started prior to running the example
// 2. 'my-second-node' -- the second node started prior to running the example
// 3. 'example-node' -- node that is embedded into the example
// 4. 'additional-node-1' -- the first node added to the topology
// 5. 'additional-node-2' -- the second node added to the topology
//
// NOTE: In the future releases, this API will be provided by the clients as well.
// In addition, the process will be automated where applicable to eliminate
// the need for this manual step.
//
//--------------------------------------------------------------------------------------
System.out.println("\nUpdating the baseline and rebalancing the data...");
server.setBaseline(Set.of(
"my-first-node",
"my-second-node",
"example-node",
"my-first-additional-node",
"my-second-additional-node"
));
//--------------------------------------------------------------------------------------
//
// Retrieving data again to validate correctness.
//
//--------------------------------------------------------------------------------------
System.out.println("\nKey-value pairs retrieved after the topology change:");
for (int i = 0; i < 10; i++) {
Tuple key = Tuple.create().set("key", i);
Tuple value = kvView.get(key);
System.out.println(" " + i + " -> " + value.stringValue("value"));
}
}
System.out.println("\nDropping the table and stopping the server...");
server.tables().dropTable(tableDef.canonicalName());
}
}
}