package com.orientechnologies.orient.server.distributed;
import com.orientechnologies.common.listener.OProgressListener;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.util.OCallable;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/*
*
* * Copyright 2015 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * Licensed 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
/**
* @author Enrico Risa
*/
public class HaSyncClusterTest extends AbstractServerClusterTest {
private final static int SERVERS = 2;
public static final int NUM_RECORDS = 1000;
ExecutorService executorService = Executors.newSingleThreadExecutor();
public String getDatabaseName() {
return "HaSyncClusterTest";
}
@Test
@Ignore
public void test() throws Exception {
init(SERVERS);
prepare(false);
execute();
}
@Override
protected void executeTest() throws Exception {
ServerRun firstServer = serverInstance.get(0);
String databasePath = firstServer.getDatabasePath(getDatabaseName());
String localNodeName = firstServer.getServerInstance().getDistributedManager().getLocalNodeName();
ODatabaseDocumentTx db = new ODatabaseDocumentTx("plocal:" + databasePath);
db.open("admin", "admin");
final OClass person = db.getMetadata().getSchema().getClass("Person");
person.createProperty("name", OType.STRING);
person.createIndex("testAutoSharding", OClass.INDEX_TYPE.UNIQUE.toString(), (OProgressListener) null, (ODocument) null,
"AUTOSHARDING", new String[] { "name" });
try {
Future<Long> future = invokeSyncCluster(localNodeName, serverInstance.get(1));
for (int i = 0; i < NUM_RECORDS; i++) {
ODocument doc = new ODocument("Person");
doc.field("name", "person" + i);
db.save(doc);
}
List<ODocument> query = db.query(new OSQLSynchQuery("select count(*) from Person"));
Long result0 = query.iterator().next().field("count");
Long result1 = future.get();
Assert.assertEquals(result1, result0);
} finally {
db.close();
}
}
protected Future<Long> invokeSyncCluster(final String localNodeName, final ServerRun server) {
Future<Long> future = executorService.submit(new Callable<Long>() {
@Override
public Long call() throws Exception {
Long countRecors = new Long(0);
String databasePath = server.getDatabasePath(getDatabaseName());
ODatabaseDocumentTx db = new ODatabaseDocumentTx("plocal:" + databasePath);
db.open("admin", "admin");
try {
ODistributedServerManager manager = server.getServerInstance().getDistributedManager();
ODistributedConfiguration databaseConfiguration = manager.getDatabaseConfiguration(getDatabaseName());
int[] persons = db.getMetadata().getSchema().getClass("Person").getClusterIds();
String clusterName = null;
for (int person : persons) {
String clusterNameById = db.getStorage().getPhysicalClusterNameById(person);
String clusterOwner = databaseConfiguration.getClusterOwner(clusterNameById);
if (clusterOwner.equals(localNodeName)) {
clusterName = clusterNameById;
break;
}
}
Assert.assertNotNull(clusterName);
db.command(new OCommandSQL(String.format("HA sync cluster %s", clusterName))).execute();
final ODistributedMessageService messageService = manager.getMessageService();
waitFor(5000, new OCallable<Boolean, Void>() {
@Override
public Boolean call(Void iArgument) {
ODocument messageStats = messageService.getMessageStats();
long heartbeat = 0;
long deploy_cluster = 0;
if (messageStats != null && messageStats.containsField("heartbeat")) {
heartbeat = messageStats.field("heartbeat");
}
if (messageStats != null && messageStats.containsField("deploy_cluster")) {
deploy_cluster = messageStats.field("deploy_cluster");
}
long processed = messageService.getProcessedRequests() - heartbeat - deploy_cluster;
OLogManager.instance()
.info(this, "Waiting for processed requests to be [%d], actual [%d] with stats [%s] ", NUM_RECORDS, processed,
messageStats.toJSON());
return processed >= NUM_RECORDS;
}
}, String.format("Number for processed request should be [%s]", NUM_RECORDS));
List<ODocument> query = db.query(new OSQLSynchQuery("select count(*) from Person"));
countRecors = query.iterator().next().field("count");
} finally {
db.close();
}
return countRecors;
}
});
return future;
}
@Override
protected void onAfterDatabaseCreation(OrientBaseGraph db) {
db.command(new OCommandSQL("CREATE CLASS Person extends V")).execute();
db.command(new OCommandSQL("CREATE PROPERTY Person.name STRING")).execute();
}
@Override
protected void waitFor(int serverId, OCallable<Boolean, ODatabaseDocumentTx> condition, long timeout) {
super.waitFor(serverId, condition, timeout);
}
}